Skip to content

Commit

Permalink
separated mutable and immutable from SelectionStrategy
Browse files Browse the repository at this point in the history
  • Loading branch information
jh3nd3rs0n committed Oct 1, 2023
1 parent ba92bce commit ec0d127
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import com.github.jh3nd3rs0n.jargyle.server.GeneralRuleResultSpecConstants;
import com.github.jh3nd3rs0n.jargyle.server.GeneralSettingSpecConstants;
import com.github.jh3nd3rs0n.jargyle.server.LogAction;
import com.github.jh3nd3rs0n.jargyle.server.SelectionStrategy;
import com.github.jh3nd3rs0n.jargyle.server.SelectionStrategySpecConstants;
import com.github.jh3nd3rs0n.jargyle.server.Setting;
import com.github.jh3nd3rs0n.jargyle.server.Socks5RuleConditionSpecConstants;
import com.github.jh3nd3rs0n.jargyle.server.Socks5RuleResultSpecConstants;
Expand Down Expand Up @@ -457,7 +457,7 @@ private void printSettingValueSyntaxes() {
System.out.println(" SCHEMES:");
this.printHelpText(Scheme.class);
System.out.println(" SELECTION_STRATEGIES:");
this.printHelpText(SelectionStrategy.class);
this.printHelpText(SelectionStrategySpecConstants.class);
System.out.println(" SOCKET_SETTINGS:");
this.printHelpText(StandardSocketSettingSpecConstants.class);
System.out.println(" SOCKS5_COMMANDS:");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public final class GeneralSettingSpecConstants {
public static final SettingSpec<SelectionStrategy> ROUTE_SELECTION_STRATEGY =
SETTING_SPECS.addThenGet(new SelectionStrategySettingSpec(
"routeSelectionStrategy",
SelectionStrategy.CYCLICAL.newMutableInstance()));
SelectionStrategySpecConstants.CYCLICAL.newSelectionStrategy()));

@HelpText(
doc = "A rule for the SOCKS server "
Expand Down
Original file line number Diff line number Diff line change
@@ -1,129 +1,38 @@
package com.github.jh3nd3rs0n.jargyle.server;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import com.github.jh3nd3rs0n.jargyle.internal.annotation.HelpText;

public abstract class SelectionStrategy {

private static final class CyclicalSelectionStrategy extends SelectionStrategy {

private int index;
private final ReentrantLock lock;

private CyclicalSelectionStrategy(final String str, final boolean mut) {
super(str, mut);
this.index = 0;
this.lock = new ReentrantLock();
}

@Override
protected <T> T implSelectFrom(final List<? extends T> list) {
T selected = null;
this.lock.lock();
try {
if (this.index > list.size() - 1) {
this.index = 0;
}
selected = list.get(this.index);
this.index++;
} finally {
this.lock.unlock();
}
return selected;
}

@Override
public SelectionStrategy newMutableInstance() {
return new CyclicalSelectionStrategy(this.toString(), true);
}

}

private static final class RandomSelectionStrategy extends SelectionStrategy {

private final ReentrantLock lock;
private final Random random;

private RandomSelectionStrategy(final String str, final boolean mut) {
super(str, mut);
this.lock = new ReentrantLock();
this.random = (mut) ? new Random() : null;
}

@Override
protected <T> T implSelectFrom(final List<? extends T> list) {
T selected = null;
this.lock.lock();
try {
selected = list.get(this.random.nextInt(list.size()));
} finally {
this.lock.unlock();
}
return selected;
}

@Override
public SelectionStrategy newMutableInstance() {
return new RandomSelectionStrategy(this.toString(), true);
}

}

private static final List<SelectionStrategy> VALUES = new ArrayList<SelectionStrategy>();
private static final Map<String, SelectionStrategy> VALUES_MAP = new HashMap<String, SelectionStrategy>();

@HelpText(
doc = "Select the next in the cycle",
usage = "CYCLICAL"
)
public static final SelectionStrategy CYCLICAL = new CyclicalSelectionStrategy("CYCLICAL", false);

@HelpText(
doc = "Select the next at random",
usage = "RANDOM"
)
public static final SelectionStrategy RANDOM = new RandomSelectionStrategy("RANDOM", false);

public static SelectionStrategy valueOf(final String s) {
if (!VALUES_MAP.containsKey(s)) {
String str = VALUES.stream()
.map(SelectionStrategy::toString)
public static SelectionStrategy newInstance(final String s) {
SelectionStrategySpec selectionStrategySpec = null;
try {
selectionStrategySpec =
SelectionStrategySpecConstants.valueOfName(s);
} catch (IllegalArgumentException e) {
String str = SelectionStrategySpecConstants.values().stream()
.map(SelectionStrategySpec::getName)
.collect(Collectors.joining(", "));
throw new IllegalArgumentException(String.format(
"expected selection strategy must be one of the "
+ "following values: %s. actual value is %s",
"expected selection strategy must be one of the following "
+ "values: %s. actual value is %s",
str,
s));
s));
}
return VALUES_MAP.get(s);
return selectionStrategySpec.newSelectionStrategy();
}

public static List<SelectionStrategy> values() {
return Collections.unmodifiableList(VALUES);
}
private final String name;
private final SelectionStrategySpec selectionStrategySpec;

private final boolean mutable;
private final String string;

SelectionStrategy(final String str, final boolean mut) {
if (!mut) {
VALUES.add(this);
VALUES_MAP.put(str, this);
}
this.mutable = mut;
this.string = str;
public SelectionStrategy(final SelectionStrategySpec spec) {
this.name = spec.getName();
this.selectionStrategySpec = spec;
}

@Override
public final boolean equals(Object obj) {
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
Expand All @@ -134,46 +43,38 @@ public final boolean equals(Object obj) {
return false;
}
SelectionStrategy other = (SelectionStrategy) obj;
if (this.string == null) {
if (other.string != null) {
if (this.name == null) {
if (other.name != null) {
return false;
}
} else if (!this.string.equals(other.string)) {
} else if (!this.name.equals(other.name)) {
return false;
}
return true;
}

public final String getName() {
return this.name;
}

public final SelectionStrategySpec getSelectionStrategySpec() {
return this.selectionStrategySpec;
}

@Override
public final int hashCode() {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.string == null) ?
0 : this.string.hashCode());
result = prime * result + ((this.name == null) ?
0 : this.name.hashCode());
return result;
}

protected abstract <T> T implSelectFrom(final List<? extends T> list);

public final boolean isMutable() {
return this.mutable;
}

public abstract SelectionStrategy newMutableInstance();

public final <T> T selectFrom(final List<? extends T> list) {
if (!this.mutable) {
throw new IllegalStateException("SelectionStrategy is not mutable");
}
if (list.size() == 0) {
return null;
}
return this.implSelectFrom(list);
}
public abstract <T> T selectFrom(final List<? extends T> list);

@Override
public final String toString() {
return this.string;
return this.name;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.github.jh3nd3rs0n.jargyle.server;

import java.util.Objects;

public abstract class SelectionStrategySpec {

private final String name;

SelectionStrategySpec(final String n) {
Objects.requireNonNull(n);
this.name = n;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
SelectionStrategySpec other = (SelectionStrategySpec) obj;
if (this.name == null) {
if (other.name != null) {
return false;
}
} else if (!this.name.equals(other.name)) {
return false;
}
return true;
}

public final String getName() {
return this.name;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.name == null) ?
0 : this.name.hashCode());
return result;
}

public abstract SelectionStrategy newSelectionStrategy();

@Override
public final String toString() {
StringBuilder builder = new StringBuilder();
builder.append(this.getClass().getSimpleName())
.append(" [name=")
.append(this.name)
.append("]");
return builder.toString();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.github.jh3nd3rs0n.jargyle.server;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.github.jh3nd3rs0n.jargyle.internal.annotation.HelpText;
import com.github.jh3nd3rs0n.jargyle.server.internal.selectionstrategy.impl.CyclicalSelectionStrategy;
import com.github.jh3nd3rs0n.jargyle.server.internal.selectionstrategy.impl.RandomSelectionStrategy;

public final class SelectionStrategySpecConstants {

private static final SelectionStrategySpecs SELECTION_STRATEGY_SPECS =
new SelectionStrategySpecs();

@HelpText(
doc = "Select the next in the cycle",
usage = "CYCLICAL"
)
public static final SelectionStrategySpec CYCLICAL = SELECTION_STRATEGY_SPECS.addThenGet(new SelectionStrategySpec(
"CYCLICAL") {

@Override
public SelectionStrategy newSelectionStrategy() {
return new CyclicalSelectionStrategy(this);
}

});

@HelpText(
doc = "Select the next at random",
usage = "RANDOM"
)
public static final SelectionStrategySpec RANDOM = SELECTION_STRATEGY_SPECS.addThenGet(new SelectionStrategySpec(
"RANDOM") {

@Override
public SelectionStrategy newSelectionStrategy() {
return new RandomSelectionStrategy(this);
}

});

private static final List<SelectionStrategySpec> VALUES =
SELECTION_STRATEGY_SPECS.toList();

private static final Map<String, SelectionStrategySpec> VALUES_MAP =
SELECTION_STRATEGY_SPECS.toMap();

public static SelectionStrategySpec valueOfName(final String name) {
if (VALUES_MAP.containsKey(name)) {
return VALUES_MAP.get(name);
}
String str = VALUES.stream()
.map(SelectionStrategySpec::getName)
.collect(Collectors.joining(", "));
throw new IllegalArgumentException(String.format(
"expected selection strategy spec must be one of the "
+ "following values: %s. actual value is %s",
str,
name));
}

public static List<SelectionStrategySpec> values() {
return VALUES;
}

public static Map<String, SelectionStrategySpec> valuesMap() {
return VALUES_MAP;
}

private SelectionStrategySpecConstants() { }

}
Loading

0 comments on commit ec0d127

Please sign in to comment.