Split providers into classes

This commit is contained in:
Jaime Martínez Rincón 2017-10-07 13:45:01 +02:00
parent 77b811f09a
commit e96640f54c
13 changed files with 341 additions and 179 deletions

View File

@ -1,8 +1,11 @@
package com.jaimemartz.playerbalancer.connection; package com.jaimemartz.playerbalancer.connection;
import com.jaimemartz.playerbalancer.PlayerBalancer; import com.jaimemartz.playerbalancer.PlayerBalancer;
import com.jaimemartz.playerbalancer.connection.provider.AbstractProvider;
import com.jaimemartz.playerbalancer.connection.provider.types.*;
import com.jaimemartz.playerbalancer.ping.ServerStatus; import com.jaimemartz.playerbalancer.ping.ServerStatus;
import com.jaimemartz.playerbalancer.section.ServerSection; import com.jaimemartz.playerbalancer.section.ServerSection;
import com.jaimemartz.playerbalancer.settings.props.features.BalancerProps;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
@ -12,97 +15,65 @@ import java.util.concurrent.ThreadLocalRandom;
public enum ProviderType { public enum ProviderType {
NONE { NONE {
NullProvider provider = new NullProvider();
@Override @Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) { public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
return null; return provider.requestTarget(plugin, section, servers, player);
} }
}, },
RANDOM { RANDOM {
RandomProvider provider = new RandomProvider();
@Override @Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) { public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
return ProviderType.getRandom(servers); return provider.requestTarget(plugin, section, servers, player);
} }
}, },
LOWEST { LOWEST {
LowestProvider provider = new LowestProvider();
@Override @Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) { public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
int min = Integer.MAX_VALUE; return provider.requestTarget(plugin, section, servers, player);
ServerInfo target = null;
for (ServerInfo server : servers) {
int count = plugin.getNetworkManager().getPlayers(server);
if (count < min) {
min = count;
target = server;
}
}
return target;
} }
}, },
BALANCED { BALANCED {
BalancedProvider provider = new BalancedProvider();
@Override @Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) { public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
List<ServerInfo> results = new ArrayList<>(); return provider.requestTarget(plugin, section, servers, player);
int min = Integer.MAX_VALUE;
for (ServerInfo server : servers) {
int count = plugin.getNetworkManager().getPlayers(server);
if (count <= min) {
if (count < min) {
min = count;
results.clear();
}
results.add(server);
}
}
return ProviderType.getRandom(results);
} }
}, },
PROGRESSIVE { PROGRESSIVE {
ProgressiveProvider provider = new ProgressiveProvider();
@Override @Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) { public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
for (ServerInfo server : servers) { return provider.requestTarget(plugin, section, servers, player);
ServerStatus status = plugin.getStatusManager().getStatus(server);
if (plugin.getNetworkManager().getPlayers(server) < status.getMaximum()) {
return server;
}
}
return ProviderType.getRandom(servers);
} }
}, },
FILLER { FILLER {
FillerProvider provider = new FillerProvider();
@Override @Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) { public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
int max = Integer.MIN_VALUE; return provider.requestTarget(plugin, section, servers, player);
ServerInfo target = null; }
},
for (ServerInfo server : servers) { EXTERNAL {
ServerStatus status = plugin.getStatusManager().getStatus(server); @Override
int count = plugin.getNetworkManager().getPlayers(server); public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
return section.getExternalProvider().requestTarget(plugin, section, servers, player);
if (count > max && count <= status.getMaximum()) {
max = count;
target = server;
}
}
return target;
} }
}; };
public abstract ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player); public abstract ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player);
private static ServerInfo getRandom(List<ServerInfo> list) {
return list.get(ThreadLocalRandom.current().nextInt(list.size()));
}
} }

View File

@ -8,6 +8,7 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.Map; import java.util.Map;
//todo improve this
public class ServerAssignRegistry { public class ServerAssignRegistry {
private static final Table<ProxiedPlayer, ServerSection, ServerInfo> table = HashBasedTable.create(); private static final Table<ProxiedPlayer, ServerSection, ServerInfo> table = HashBasedTable.create();

View File

@ -0,0 +1,17 @@
package com.jaimemartz.playerbalancer.connection.provider;
import com.jaimemartz.playerbalancer.PlayerBalancer;
import com.jaimemartz.playerbalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.List;
public abstract class AbstractProvider {
public abstract ServerInfo requestTarget(
PlayerBalancer plugin,
ServerSection section,
List<ServerInfo> servers,
ProxiedPlayer player
);
}

View File

@ -0,0 +1,33 @@
package com.jaimemartz.playerbalancer.connection.provider.types;
import com.jaimemartz.playerbalancer.PlayerBalancer;
import com.jaimemartz.playerbalancer.connection.provider.AbstractProvider;
import com.jaimemartz.playerbalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class BalancedProvider extends AbstractProvider {
@Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
List<ServerInfo> results = new ArrayList<>();
int min = Integer.MAX_VALUE;
for (ServerInfo server : servers) {
int count = plugin.getNetworkManager().getPlayers(server);
if (count <= min) {
if (count < min) {
min = count;
results.clear();
}
results.add(server);
}
}
return results.get(ThreadLocalRandom.current().nextInt(results.size()));
}
}

View File

@ -0,0 +1,30 @@
package com.jaimemartz.playerbalancer.connection.provider.types;
import com.jaimemartz.playerbalancer.PlayerBalancer;
import com.jaimemartz.playerbalancer.connection.provider.AbstractProvider;
import com.jaimemartz.playerbalancer.ping.ServerStatus;
import com.jaimemartz.playerbalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.List;
public class FillerProvider extends AbstractProvider {
@Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
int max = Integer.MIN_VALUE;
ServerInfo target = null;
for (ServerInfo server : servers) {
ServerStatus status = plugin.getStatusManager().getStatus(server);
int count = plugin.getNetworkManager().getPlayers(server);
if (count > max && count <= status.getMaximum()) {
max = count;
target = server;
}
}
return target;
}
}

View File

@ -0,0 +1,28 @@
package com.jaimemartz.playerbalancer.connection.provider.types;
import com.jaimemartz.playerbalancer.PlayerBalancer;
import com.jaimemartz.playerbalancer.connection.provider.AbstractProvider;
import com.jaimemartz.playerbalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.List;
public class LowestProvider extends AbstractProvider {
@Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
int min = Integer.MAX_VALUE;
ServerInfo target = null;
for (ServerInfo server : servers) {
int count = plugin.getNetworkManager().getPlayers(server);
if (count < min) {
min = count;
target = server;
}
}
return target;
}
}

View File

@ -0,0 +1,16 @@
package com.jaimemartz.playerbalancer.connection.provider.types;
import com.jaimemartz.playerbalancer.PlayerBalancer;
import com.jaimemartz.playerbalancer.connection.provider.AbstractProvider;
import com.jaimemartz.playerbalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.List;
public class NullProvider extends AbstractProvider {
@Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
return null;
}
}

View File

@ -0,0 +1,26 @@
package com.jaimemartz.playerbalancer.connection.provider.types;
import com.jaimemartz.playerbalancer.PlayerBalancer;
import com.jaimemartz.playerbalancer.connection.ProviderType;
import com.jaimemartz.playerbalancer.connection.provider.AbstractProvider;
import com.jaimemartz.playerbalancer.ping.ServerStatus;
import com.jaimemartz.playerbalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class ProgressiveProvider extends AbstractProvider {
@Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
for (ServerInfo server : servers) {
ServerStatus status = plugin.getStatusManager().getStatus(server);
if (plugin.getNetworkManager().getPlayers(server) < status.getMaximum()) {
return server;
}
}
return servers.get(ThreadLocalRandom.current().nextInt(servers.size()));
}
}

View File

@ -0,0 +1,17 @@
package com.jaimemartz.playerbalancer.connection.provider.types;
import com.jaimemartz.playerbalancer.PlayerBalancer;
import com.jaimemartz.playerbalancer.connection.provider.AbstractProvider;
import com.jaimemartz.playerbalancer.section.ServerSection;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class RandomProvider extends AbstractProvider {
@Override
public ServerInfo requestTarget(PlayerBalancer plugin, ServerSection section, List<ServerInfo> servers, ProxiedPlayer player) {
return servers.get(ThreadLocalRandom.current().nextInt(servers.size()));
}
}

View File

@ -15,17 +15,18 @@ import java.io.FileInputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Supplier;
public enum PasteHelper { public enum PasteHelper {
PLUGIN((sender, url) -> { PLUGIN((sender, address) -> {
if (sender instanceof ProxiedPlayer) { if (sender instanceof ProxiedPlayer) {
sender.sendMessage(new ComponentBuilder("Click me for the PlayerBalancer configuration") sender.sendMessage(new ComponentBuilder("Click me for the PlayerBalancer configuration")
.event(new ClickEvent(ClickEvent.Action.OPEN_URL, url.toString())) .event(new ClickEvent(ClickEvent.Action.OPEN_URL, address.toString()))
.color(ChatColor.GREEN) .color(ChatColor.GREEN)
.create() .create()
); );
} else { } else {
sender.sendMessage(new ComponentBuilder("PlayerBalancer configuration link: " + url.toString()).create()); sender.sendMessage(new ComponentBuilder("PlayerBalancer configuration link: " + address.toString()).create());
} }
}) { }) {
@Override @Override
@ -52,15 +53,15 @@ public enum PasteHelper {
} }
}, },
BUNGEE((sender, url) -> { BUNGEE((sender, address) -> {
if (sender instanceof ProxiedPlayer) { if (sender instanceof ProxiedPlayer) {
sender.sendMessage(new ComponentBuilder("Click me for the BungeeCord configuration") sender.sendMessage(new ComponentBuilder("Click me for the BungeeCord configuration")
.event(new ClickEvent(ClickEvent.Action.OPEN_URL, url.toString())) .event(new ClickEvent(ClickEvent.Action.OPEN_URL, address.toString()))
.color(ChatColor.GREEN) .color(ChatColor.GREEN)
.create() .create()
); );
} else { } else {
sender.sendMessage(new ComponentBuilder("BungeeCord configuration link: " + url.toString()).create()); sender.sendMessage(new ComponentBuilder("BungeeCord configuration link: " + address.toString()).create());
} }
}) { }) {
@Override @Override

View File

@ -7,7 +7,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
//TODO I don't like it, improve it //TODO improve this
public class PlayerLocker { public class PlayerLocker {
private static final Set<UUID> storage = Collections.synchronizedSet(new HashSet<UUID>()); private static final Set<UUID> storage = Collections.synchronizedSet(new HashSet<UUID>());

View File

@ -22,6 +22,7 @@ public class SectionManager {
private ServerSection principal; private ServerSection principal;
private ScheduledTask refreshTask; private ScheduledTask refreshTask;
private final Map<String, Stage> stages = Collections.synchronizedMap(new HashMap<>());
private final Map<String, ServerSection> sections = Collections.synchronizedMap(new HashMap<>()); private final Map<String, ServerSection> sections = Collections.synchronizedMap(new HashMap<>());
private final Map<ServerInfo, ServerSection> servers = Collections.synchronizedMap(new HashMap<>()); private final Map<ServerInfo, ServerSection> servers = Collections.synchronizedMap(new HashMap<>());
@ -34,10 +35,131 @@ public class SectionManager {
plugin.getLogger().info("Executing section initialization stages, this may take a while..."); plugin.getLogger().info("Executing section initialization stages, this may take a while...");
long starting = System.currentTimeMillis(); long starting = System.currentTimeMillis();
for (Stage stage : stages) { stages.put("constructing-sections", new SectionStage("Constructing sections") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
ServerSection object = new ServerSection(sectionName, sectionProps);
sections.put(sectionName, object);
}
});
stages.put("processing-principal-section", new Stage("Processing principal section") {
@Override
public void execute() {
principal = sections.get(props.getPrincipalSectionName());
if (principal == null) {
throw new IllegalArgumentException(String.format(
"Could not set principal section, there is no section called \"%s\"",
props.getPrincipalSectionName()
));
}
}
});
stages.put("processing-parents", new SectionStage("Processing parents") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
if (sectionProps.getParentName() != null) {
ServerSection parent = getByName(sectionProps.getParentName());
if (principal.equals(section) && parent == null) {
throw new IllegalArgumentException(String.format(
"The section \"%s\" has an invalid parent set",
section.getName()
));
} else {
section.setParent(parent);
}
}
}
});
stages.put("validating-parents", new SectionStage("Validating parents") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
ServerSection parent = section.getParent();
if (parent != null && parent.getParent() == section) {
throw new IllegalStateException(String.format(
"The sections \"%s\" and \"%s\" are parents of each other",
section.getName(),
parent.getName()
));
}
}
});
stages.put("validating-providers", new SectionStage("Validating providers") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
if (sectionProps.getProvider() == null) {
ServerSection current = section.getParent();
if (current != null) {
while (current.getExplicitProvider() == null) {
current = current.getParent();
}
plugin.getLogger().info(String.format(
"The section \"%s\" inherits the provider from the section \"%s\"",
section.getName(),
current.getName()
));
section.setInherited(true);
}
} else {
section.setInherited(false);
}
}
});
stages.put("calculating-positions", new SectionStage("Calculating positions") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
section.setPosition(calculatePosition(section));
}
});
stages.put("resolving-servers", new SectionStage("Resolving servers") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
calculateServers(section);
}
});
stages.put("section-server-processing", new SectionStage("Section server processing") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
if (sectionProps.getServerName() != null) {
SectionServer server = new SectionServer(props, section);
section.setServer(server);
plugin.getSectionManager().register(server, section);
FixedAdapter.getFakeServers().put(server.getName(), server);
plugin.getProxy().getServers().put(server.getName(), server);
}
}
});
stages.put("section-command-processing", new SectionStage("Section command processing") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
if (sectionProps.getCommandProps() != null) {
SectionCommand command = new SectionCommand(plugin, section);
section.setCommand(command);
plugin.getProxy().getPluginManager().registerCommand(plugin, command);
}
}
});
stages.put("finishing-loading", new SectionStage("Finishing loading sections") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
section.setValid(true);
}
});
stages.forEach((name, stage) -> {
plugin.getLogger().info("Executing stage \"" + stage.title + "\""); plugin.getLogger().info("Executing stage \"" + stage.title + "\"");
stage.execute(); stage.execute();
} });
if (plugin.getSettings().getServerRefreshProps().isEnabled()) { if (plugin.getSettings().getServerRefreshProps().isEnabled()) {
plugin.getLogger().info("Starting automatic server refresh task"); plugin.getLogger().info("Starting automatic server refresh task");
@ -136,120 +258,6 @@ public class SectionManager {
return getByServer(server.getInfo()); return getByServer(server.getInfo());
} }
private final Stage[] stages = {
new SectionStage("Constructing sections") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
ServerSection object = new ServerSection(sectionName, sectionProps);
sections.put(sectionName, object);
}
},
new Stage("Processing principal section") {
@Override
public void execute() {
principal = sections.get(props.getPrincipalSectionName());
if (principal == null) {
throw new IllegalArgumentException(String.format(
"Could not set principal section, there is no section called \"%s\"",
props.getPrincipalSectionName()
));
}
}
},
new SectionStage("Processing parents") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
if (sectionProps.getParentName() != null) {
ServerSection parent = getByName(sectionProps.getParentName());
if (principal.equals(section) && parent == null) {
throw new IllegalArgumentException(String.format(
"The section \"%s\" has an invalid parent set",
section.getName()
));
} else {
section.setParent(parent);
}
}
}
},
new SectionStage("Validating parents") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
ServerSection parent = section.getParent();
if (parent != null && parent.getParent() == section) {
throw new IllegalStateException(String.format(
"The sections \"%s\" and \"%s\" are parents of each other",
section.getName(),
parent.getName()
));
}
}
},
new SectionStage("Validating providers") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
if (sectionProps.getProvider() == null) {
ServerSection current = section.getParent();
if (current != null) {
while (current.getExplicitProvider() == null) {
current = current.getParent();
}
plugin.getLogger().info(String.format(
"The section \"%s\" inherits the provider from the section \"%s\"",
section.getName(),
current.getName()
));
section.setInherited(true);
}
} else {
section.setInherited(false);
}
}
},
new SectionStage("Calculating positions") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
section.setPosition(calculatePosition(section));
}
},
new SectionStage("Resolving servers") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
calculateServers(section);
}
},
new SectionStage("Section server processing") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
if (sectionProps.getServerName() != null) {
SectionServer server = new SectionServer(props, section);
section.setServer(server);
plugin.getSectionManager().register(server, section);
FixedAdapter.getFakeServers().put(server.getName(), server);
plugin.getProxy().getServers().put(server.getName(), server);
}
}
},
new SectionStage("Section command processing") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
if (sectionProps.getCommandProps() != null) {
SectionCommand command = new SectionCommand(plugin, section);
section.setCommand(command);
plugin.getProxy().getPluginManager().registerCommand(plugin, command);
}
}
},
new SectionStage("Finishing loading sections") {
@Override
public void execute(String sectionName, SectionProps sectionProps, ServerSection section) throws RuntimeException {
section.setValid(true);
}
},
};
public void calculateServers(ServerSection section) { public void calculateServers(ServerSection section) {
Set<ServerInfo> results = new HashSet<>(); Set<ServerInfo> results = new HashSet<>();
@ -352,6 +360,10 @@ public class SectionManager {
return sections; return sections;
} }
public Stage getStage(String name) {
return stages.get(name);
}
private abstract class Stage { private abstract class Stage {
private final String title; private final String title;

View File

@ -1,6 +1,7 @@
package com.jaimemartz.playerbalancer.section; package com.jaimemartz.playerbalancer.section;
import com.jaimemartz.playerbalancer.connection.ProviderType; import com.jaimemartz.playerbalancer.connection.ProviderType;
import com.jaimemartz.playerbalancer.connection.provider.AbstractProvider;
import com.jaimemartz.playerbalancer.settings.props.shared.SectionProps; import com.jaimemartz.playerbalancer.settings.props.shared.SectionProps;
import com.jaimemartz.playerbalancer.utils.AlphanumComparator; import com.jaimemartz.playerbalancer.utils.AlphanumComparator;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
@ -20,6 +21,7 @@ public class ServerSection {
private ServerInfo server; private ServerInfo server;
private SectionCommand command; private SectionCommand command;
private Set<ServerInfo> servers; private Set<ServerInfo> servers;
private AbstractProvider externalProvider;
private boolean valid = false; private boolean valid = false;
@ -82,6 +84,14 @@ public class ServerSection {
inherited = false; inherited = false;
} }
public void setExternalProvider(AbstractProvider externalProvider) {
this.externalProvider = externalProvider;
}
public AbstractProvider getExternalProvider() {
return externalProvider;
}
public ServerInfo getServer() { public ServerInfo getServer() {
return server; return server;
} }