![JAR search and dependency download from the Maven repository](/logo.png)
org.dasein.cloud.rackspace.compute.CloudServers Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dasein-cloud-rackspace Show documentation
Show all versions of dasein-cloud-rackspace Show documentation
Native API implementation for the Rackspace API
The newest version!
/**
* Copyright (C) 2009-2012 enStratus Networks Inc
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.dasein.cloud.rackspace.compute;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dasein.cloud.CloudErrorType;
import org.dasein.cloud.CloudException;
import org.dasein.cloud.InternalException;
import org.dasein.cloud.OperationNotSupportedException;
import org.dasein.cloud.ProviderContext;
import org.dasein.cloud.Requirement;
import org.dasein.cloud.ResourceStatus;
import org.dasein.cloud.Tag;
import org.dasein.cloud.compute.Architecture;
import org.dasein.cloud.compute.ImageClass;
import org.dasein.cloud.compute.MachineImage;
import org.dasein.cloud.compute.Platform;
import org.dasein.cloud.compute.VMLaunchOptions;
import org.dasein.cloud.compute.VMScalingCapabilities;
import org.dasein.cloud.compute.VMScalingOptions;
import org.dasein.cloud.compute.VirtualMachine;
import org.dasein.cloud.compute.VirtualMachineProduct;
import org.dasein.cloud.compute.VirtualMachineSupport;
import org.dasein.cloud.compute.VmState;
import org.dasein.cloud.compute.VmStatistics;
import org.dasein.cloud.dc.DataCenter;
import org.dasein.cloud.identity.ServiceAction;
import org.dasein.cloud.rackspace.RackspaceCloud;
import org.dasein.cloud.rackspace.RackspaceException;
import org.dasein.cloud.rackspace.RackspaceMethod;
import org.dasein.util.CalendarWrapper;
import org.dasein.util.uom.storage.Gigabyte;
import org.dasein.util.uom.storage.Megabyte;
import org.dasein.util.uom.storage.Storage;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class CloudServers implements VirtualMachineSupport {
static private HashMap> cachedProducts = new HashMap>();
static public final int NAME_LIMIT = 30;
static public final int TAG_LIMIT = 4;
private RackspaceCloud provider;
CloudServers(@Nonnull RackspaceCloud provider) { this.provider = provider; }
@Override
public VirtualMachine alterVirtualMachine(@Nonnull String vmId, @Nonnull VMScalingOptions options) throws InternalException, CloudException {
throw new OperationNotSupportedException("Not supported");
}
@Override
public @Nonnull VirtualMachine clone(@Nonnull String vmId, @Nullable String intoDcId, @Nonnull String name, @Nonnull String description, boolean powerOn, @Nullable String... firewallIds) throws InternalException, CloudException {
throw new OperationNotSupportedException("Rackspace foes not support the cloning of servers.");
}
@Override
public VMScalingCapabilities describeVerticalScalingCapabilities() throws CloudException, InternalException {
return null;
}
@Override
public void disableAnalytics(@Nonnull String vmId) throws InternalException, CloudException {
// NO-OP
}
@Override
public void enableAnalytics(@Nonnull String vmId) throws InternalException, CloudException {
// NO-OP
}
@Override
public @Nonnull String getConsoleOutput(@Nonnull String vmId) throws InternalException, CloudException {
return "";
}
@Override
public int getCostFactor(@Nonnull VmState state) throws InternalException, CloudException {
return 100;
}
@Override
public int getMaximumVirtualMachineCount() throws CloudException, InternalException {
return -2;
}
@Override
public @Nullable VirtualMachineProduct getProduct(@Nonnull String productId) throws InternalException, CloudException {
Logger std = RackspaceCloud.getLogger(CloudServers.class, "std");
if( std.isTraceEnabled() ) {
std.trace("enter - " + CloudServers.class.getName() + ".getProduct(" + productId + ")");
}
try {
if( !provider.isMyRegion() ) {
return null;
}
for( VirtualMachineProduct product : listProducts(Architecture.I64) ) {
if( product.getProviderProductId().equals(productId) ) {
return product;
}
}
return null;
}
finally {
if( std.isTraceEnabled() ) {
std.trace("exit - " + CloudServers.class.getName() + ".getProduct()");
}
}
}
@Override
public @Nonnull String getProviderTermForServer(@Nonnull Locale locale) {
return "server";
}
@Override
public @Nullable VirtualMachine getVirtualMachine(@Nonnull String vmId) throws InternalException, CloudException {
Logger std = RackspaceCloud.getLogger(CloudServers.class, "std");
if( std.isTraceEnabled() ) {
std.trace("enter - " + CloudServers.class.getName() + ".getVirtualMachine(" + vmId + ")");
}
try {
/*
if( !provider.isMyRegion() ) {
return null;
}
*/
RackspaceMethod method = new RackspaceMethod(provider);
JSONObject ob = method.getServers("/servers", vmId);
if( ob == null ) {
return null;
}
try {
if( ob.has("server") ) {
JSONObject server = ob.getJSONObject("server");
VirtualMachine vm = toVirtualMachine(server);
if( vm != null ) {
return vm;
}
}
}
catch( JSONException e ) {
std.error("getVirtualMachine(): Unable to identify expected values in JSON: " + e.getMessage());
throw new CloudException(CloudErrorType.COMMUNICATION, 200, "invalidJson", "Missing JSON element for servers");
}
return null;
}
finally {
if( std.isTraceEnabled() ) {
std.trace("exit - " + CloudServers.class.getName() + ".getVirtualMachine()");
}
}
}
@Override
public @Nullable VmStatistics getVMStatistics(@Nonnull String vmId, long from, long to) throws InternalException, CloudException {
return null;
}
@Override
public @Nonnull Iterable getVMStatisticsForPeriod(@Nonnull String vmId, long from, long to) throws InternalException, CloudException {
return Collections.emptyList();
}
@Nonnull
@Override
public Requirement identifyImageRequirement(@Nonnull ImageClass cls) throws CloudException, InternalException {
return (cls.equals(ImageClass.MACHINE) ? Requirement.REQUIRED : Requirement.NONE);
}
@Override
public @Nonnull Requirement identifyPasswordRequirement() throws CloudException, InternalException {
return Requirement.NONE;
}
@Nonnull
@Override
public Requirement identifyPasswordRequirement(Platform platform) throws CloudException, InternalException {
return Requirement.NONE;
}
@Override
public @Nonnull Requirement identifyRootVolumeRequirement() throws CloudException, InternalException {
return Requirement.NONE;
}
@Override
public @Nonnull Requirement identifyShellKeyRequirement() throws CloudException, InternalException {
return Requirement.NONE;
}
@Nonnull
@Override
public Requirement identifyShellKeyRequirement(Platform platform) throws CloudException, InternalException {
return Requirement.NONE;
}
@Nonnull
@Override
public Requirement identifyStaticIPRequirement() throws CloudException, InternalException {
return Requirement.NONE;
}
@Override
public @Nonnull Requirement identifyVlanRequirement() throws CloudException, InternalException {
return Requirement.NONE;
}
@Override
public boolean isAPITerminationPreventable() throws CloudException, InternalException {
return false;
}
@Override
public boolean isBasicAnalyticsSupported() throws CloudException, InternalException {
return false;
}
@Override
public boolean isExtendedAnalyticsSupported() throws CloudException, InternalException {
return false;
}
@Override
public boolean isSubscribed() throws CloudException, InternalException {
return (provider.isMyRegion() && provider.testContext() != null);
}
@Override
public boolean isUserDataSupported() throws CloudException, InternalException {
return false;
}
@Override
public @Nonnull VirtualMachine launch(@Nonnull VMLaunchOptions withLaunchOptions) throws CloudException, InternalException {
Logger logger = RackspaceCloud.getLogger(CloudServers.class, "std");
if( logger.isTraceEnabled() ) {
logger.trace("enter - " + CloudServers.class.getName() + ".launch(" + withLaunchOptions + ")");
}
try {
if( !provider.isMyRegion() ) {
throw new CloudException("Unable to launch any servers in " + provider.getContext().getRegionId());
}
String fromMachineImageId = withLaunchOptions.getMachineImageId();
String productId = withLaunchOptions.getStandardProductId();
Map meta = withLaunchOptions.getMetaData();
MachineImage targetImage = provider.getComputeServices().getImageSupport().getImage(fromMachineImageId);
HashMap wrapper = new HashMap();
HashMap json = new HashMap();
json.put("imageId", Long.parseLong(fromMachineImageId));
json.put("flavorId", Long.parseLong(productId));
HashMap metaData = new HashMap();
boolean safeName = false;
int tagCount = 0;
if( meta != null ) {
for( Map.Entry tag : meta.entrySet() ) {
if( tag.getKey() != null && tag.getValue() != null && tag.getKey().length() > 0 && tag.getValue().toString().length() > 0 ) {
metaData.put(tag.getKey(), tag.getValue());
tagCount++;
if( tagCount >= TAG_LIMIT ) {
break;
}
}
}
}
if( tagCount < TAG_LIMIT && !targetImage.getPlatform().equals(Platform.UNKNOWN) ) {
metaData.put("dsnPlatform", targetImage.getPlatform().name());
tagCount++;
}
if( tagCount < TAG_LIMIT ) {
metaData.put("dsnDescription", withLaunchOptions.getDescription());
tagCount++;
}
if( tagCount < TAG_LIMIT ) {
metaData.put("dsnName", withLaunchOptions.getFriendlyName());
safeName = true;
}
metaData.put("dsnTrueImage", targetImage.getProviderMachineImageId());
json.put("metadata", metaData);
json.put("name", validateName(withLaunchOptions.getHostName(), safeName));
wrapper.put("server", json);
RackspaceMethod method = new RackspaceMethod(provider);
JSONObject result = method.postServers("/servers", null, new JSONObject(wrapper));
if( result.has("server") ) {
try {
JSONObject server = result.getJSONObject("server");
VirtualMachine vm = toVirtualMachine(server);
if( vm != null ) {
return vm;
}
}
catch( JSONException e ) {
logger.error("launch(): Unable to understand launch response: " + e.getMessage());
if( logger.isTraceEnabled() ) {
e.printStackTrace();
}
throw new CloudException(e);
}
}
logger.error("launch(): No server was created by the launch attempt, and no error was returned");
throw new CloudException("No virtual machine was launched");
}
finally {
if( logger.isTraceEnabled() ) {
logger.trace("exit - " + CloudServers.class.getName() + ".launch()");
}
}
}
@Override
public @Nonnull VirtualMachine launch(@Nonnull String fromMachineImageId, @Nonnull VirtualMachineProduct product, @Nullable String dataCenterId, @Nonnull String name, @Nonnull String description, @Nullable String withKeypairId, @Nullable String inVlanId, boolean withAnalytics, boolean asSandbox, @Nullable String... firewallIds) throws InternalException, CloudException {
return launch(fromMachineImageId, product, dataCenterId, name, description, withKeypairId, inVlanId, withAnalytics, asSandbox, firewallIds, new Tag[0]);
}
@Override
public @Nonnull VirtualMachine launch(@Nonnull String fromMachineImageId, @Nonnull VirtualMachineProduct product, @Nullable String dataCenterId, @Nonnull String name, @Nonnull String description, @Nullable String withKeypairId, @Nullable String inVlanId, boolean withAnalytics, boolean asSandbox, @Nullable String[] firewallIds, @Nullable Tag... tags) throws InternalException, CloudException {
ProviderContext ctx = provider.getContext();
if( ctx == null ) {
throw new CloudException("No context was provided for this request");
}
//noinspection ConstantConditions
if( description == null ) {
description = name;
}
if( dataCenterId == null ) {
for( DataCenter dc : provider.getDataCenterServices().listDataCenters(ctx.getRegionId()) ) {
if( dc != null ) {
dataCenterId = dc.getProviderDataCenterId();
break;
}
}
}
VMLaunchOptions options;
if( inVlanId == null ) {
//noinspection ConstantConditions
options = VMLaunchOptions.getInstance(product.getProviderProductId(), fromMachineImageId, name, description).inDataCenter(dataCenterId);
}
else {
//noinspection ConstantConditions
options = VMLaunchOptions.getInstance(product.getProviderProductId(), fromMachineImageId, name, description).inVlan(null, dataCenterId, inVlanId);
}
if( withKeypairId != null ) {
options = options.withBoostrapKey(withKeypairId);
}
if( tags != null ) {
for( Tag t : tags ) {
options = options.withMetaData(t.getKey(), t.getValue());
}
}
if( firewallIds != null ) {
options = options.behindFirewalls(firewallIds);
}
return launch(options);
}
@Override
public @Nonnull Iterable listFirewalls(@Nonnull String vmId) throws InternalException, CloudException {
return Collections.emptyList();
}
@Override
public @Nonnull Iterable listProducts(@Nonnull Architecture architecture) throws InternalException, CloudException {
Logger std = RackspaceCloud.getLogger(CloudServers.class, "std");
if( std.isTraceEnabled() ) {
std.trace("enter - " + CloudServers.class.getName() + ".listProducts()");
}
try {
if( !provider.isMyRegion() ) {
return Collections.emptyList();
}
if( architecture.equals(Architecture.I32) ) {
return Collections.emptyList();
}
Collection products = cachedProducts.get(provider.getContext().getRegionId());
if( products == null ) {
if( std.isDebugEnabled() ) {
std.debug("listProducts(): Cache for " + provider.getContext().getRegionId() + " is empty, fetching values from cloud");
}
RackspaceMethod method = new RackspaceMethod(provider);
JSONObject ob = method.getServers("/flavors", null);
products = new ArrayList();
try {
if( ob.has("flavors") ) {
JSONArray list = ob.getJSONArray("flavors");
for( int i=0; i architectures;
@Override
public Iterable listSupportedArchitectures() throws InternalException, CloudException {
if( architectures == null ) {
ArrayList tmp = new ArrayList();
tmp.add(Architecture.I32);
tmp.add(Architecture.I64);
architectures = Collections.unmodifiableList(tmp);
}
return architectures;
}
@Nonnull
@Override
public Iterable listVirtualMachineStatus() throws InternalException, CloudException {
ArrayList status = new ArrayList();
for( VirtualMachine vm : listVirtualMachines() ) {
status.add(new ResourceStatus(vm.getProviderVirtualMachineId(), vm.getCurrentState()));
}
return status;
}
@Override
public @Nonnull Iterable listVirtualMachines() throws InternalException, CloudException {
Logger std = RackspaceCloud.getLogger(CloudServers.class, "std");
if( std.isTraceEnabled() ) {
std.trace("enter - " + CloudServers.class.getName() + ".listVirtualMachines()");
}
try {
if( !provider.isMyRegion() ) {
return Collections.emptyList();
}
RackspaceMethod method = new RackspaceMethod(provider);
JSONObject ob = method.getServers("/servers", null);
ArrayList servers = new ArrayList();
try {
if( ob.has("servers") ) {
JSONArray list = ob.getJSONArray("servers");
for( int i=0; i json = new HashMap();
HashMap action = new HashMap();
action.put("type", "HARD");
json.put("reboot", action);
RackspaceMethod method = new RackspaceMethod(provider);
method.postServers("/servers", vmId, new JSONObject(json));
}
finally {
if( logger.isTraceEnabled() ) {
logger.trace("exit - " + CloudServers.class.getName() + ".reboot()");
}
}
}
@Override
public void resume(@Nonnull String vmId) throws CloudException, InternalException {
throw new OperationNotSupportedException("Rackspace does not support suspend/resume of servers.");
}
@Override
public void start(@Nonnull String vmId) throws InternalException, CloudException {
throw new OperationNotSupportedException("Rackspace does not support start/stop of servers.");
}
@Override
public void stop(@Nonnull String vmId) throws InternalException, CloudException {
stop(vmId, false);
}
@Override
public void stop(@Nonnull String vmId, boolean force) throws InternalException, CloudException {
throw new OperationNotSupportedException("Rackspace does not support start/stop of servers");
}
@Override
public boolean supportsAnalytics() throws CloudException, InternalException {
return false;
}
@Override
public boolean supportsPauseUnpause(@Nonnull VirtualMachine vm) {
return false;
}
@Override
public boolean supportsStartStop(@Nonnull VirtualMachine vm) {
return false;
}
@Override
public boolean supportsSuspendResume(@Nonnull VirtualMachine vm) {
return false;
}
@Override
public void suspend(@Nonnull String vmId) throws CloudException, InternalException {
throw new OperationNotSupportedException("Rackspace does not support suspend/resume of servers.");
}
@Override
public void terminate(@Nonnull String vmId) throws InternalException, CloudException {
Logger std = RackspaceCloud.getLogger(CloudServers.class, "std");
if( std.isTraceEnabled() ) {
std.trace("enter - " + CloudServers.class.getName() + ".terminate(" + vmId + ")");
}
try {
RackspaceMethod method = new RackspaceMethod(provider);
long timeout = System.currentTimeMillis() + CalendarWrapper.HOUR;
do {
try {
method.deleteServers("/servers", vmId);
return;
}
catch( RackspaceException e ) {
if( e.getHttpCode() != HttpServletResponse.SC_CONFLICT ) {
throw e;
}
}
try { Thread.sleep(CalendarWrapper.MINUTE); }
catch( InterruptedException e ) { /* ignore */ }
} while( System.currentTimeMillis() < timeout );
}
finally {
if( std.isTraceEnabled() ) {
std.trace("exit - " + CloudServers.class.getName() + ".terminate()");
}
}
}
@Override
public void unpause(@Nonnull String vmId) throws CloudException, InternalException {
throw new OperationNotSupportedException("Rackspace does not support pause/unpause.");
}
@Override
public void updateTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException {
// NO-OP
}
private @Nullable VirtualMachineProduct toProduct(@Nullable JSONObject json) throws JSONException, InternalException, CloudException {
Logger std = RackspaceCloud.getLogger(CloudServers.class, "std");
if( std.isTraceEnabled() ) {
std.trace("enter - " + CloudServers.class.getName() + ".toProduct(" + json + ")");
}
try {
if( json == null ) {
return null;
}
VirtualMachineProduct product = new VirtualMachineProduct();
if( json.has("id") ) {
product.setProviderProductId(json.getString("id"));
}
if( json.has("name") ) {
product.setName(json.getString("name"));
}
if( json.has("description") ) {
product.setDescription(json.getString("description"));
}
if( json.has("ram") ) {
product.setRamSize(new Storage(json.getInt("ram"), Storage.MEGABYTE));
}
if( json.has("disk") ) {
product.setRootVolumeSize(new Storage(json.getInt("disk"), Storage.GIGABYTE));
}
product.setCpuCount(1);
if( product.getProviderProductId() == null ) {
return null;
}
if( product.getName() == null ) {
product.setName(product.getProviderProductId());
}
if( product.getDescription() == null ) {
product.setDescription(product.getName());
}
return product;
}
finally {
if( std.isTraceEnabled() ) {
std.trace("enter - " + CloudServers.class.getName() + ".toProduct()");
}
}
}
private @Nullable VirtualMachine toVirtualMachine(@Nullable JSONObject server) throws JSONException, InternalException, CloudException {
Logger std = RackspaceCloud.getLogger(CloudServers.class, "std");
if( std.isTraceEnabled() ) {
std.trace("enter - " + CloudServers.class.getName() + ".toVirtualMachine(" + server + ")");
}
try {
if( server == null ) {
return null;
}
VirtualMachine vm = new VirtualMachine();
vm.setCurrentState(VmState.RUNNING);
vm.setArchitecture(Architecture.I64);
vm.setClonable(false);
vm.setCreationTimestamp(-1L);
vm.setImagable(false);
vm.setLastBootTimestamp(-1L);
vm.setLastPauseTimestamp(-1L);
vm.setPausable(false);
vm.setPersistent(true);
vm.setPlatform(Platform.UNKNOWN);
vm.setRebootable(true);
vm.setProviderOwnerId(provider.getContext().getAccountNumber());
if( server.has("id") ) {
vm.setProviderVirtualMachineId(String.valueOf(server.getLong("id")));
}
if( server.has("name") ) {
vm.setName(server.getString("name"));
}
if( server.has("description") ) {
vm.setDescription(server.getString("description"));
}
if( server.has("imageId") ) {
vm.setProviderMachineImageId(server.getString("imageId"));
}
if( vm.getDescription() == null ) {
HashMap map = new HashMap();
if( server.has("metadata") ) {
JSONObject md = server.getJSONObject("metadata");
if( md.has("dsnDescription") ) {
vm.setDescription(md.getString("dsnDescription"));
}
else if( md.has("dsnTrueImage") ) { // this will override the nonsense Rackspace is sending us
String imageId = md.getString("dsnTrueImage");
if( imageId != null && imageId.length() > 0 ) {
vm.setProviderMachineImageId(imageId);
}
}
else if( md.has("Server Label") ) {
vm.setDescription(md.getString("Server Label"));
}
if( md.has("dsnName") ) {
String str = md.getString("dsnName");
if( str != null && str.length() > 0 ) {
vm.setName(str);
}
}
if( md.has("dsnPlatform") ) {
try {
vm.setPlatform(Platform.valueOf(md.getString("dsnPlatform")));
}
catch( Throwable ignore ) {
// ignore
}
}
String[] keys = JSONObject.getNames(md);
if( keys != null ) {
for( String key : keys ) {
String value = md.getString(key);
if( value != null ) {
map.put(key, value);
}
}
}
}
if( vm.getDescription() == null ) {
if( vm.getName() == null ) {
vm.setName(vm.getProviderVirtualMachineId());
}
vm.setDescription(vm.getName());
}
if( server.has("hostId") ) {
map.put("host", server.getString("hostId"));
}
vm.setTags(map);
}
if( server.has("flavorId") ) {
vm.setProductId(server.getString("flavorId"));
}
if( server.has("adminPass") ) {
vm.setRootPassword(server.getString("adminPass"));
}
if( server.has("status") ) {
String s = server.getString("status").toLowerCase();
if( s.equals("active") ) {
vm.setCurrentState(VmState.RUNNING);
}
else if( s.equals("building") || s.equals("build") ) {
vm.setCurrentState(VmState.PENDING);
}
else if( s.equals("deleted") ) {
vm.setCurrentState(VmState.TERMINATED);
}
else if( s.equals("suspended") ) {
vm.setCurrentState(VmState.SUSPENDED);
}
else if( s.equals("error") ) {
return null;
}
else if( s.equals("reboot") || s.equals("hard_reboot") ) {
vm.setCurrentState(VmState.REBOOTING);
}
else {
std.warn("toVirtualMachine(): Unknown server state: " + s);
vm.setCurrentState(VmState.PENDING);
}
}
if( server.has("addresses") ) {
JSONObject addrs = server.getJSONObject("addresses");
if( addrs.has("public") ) {
JSONArray arr = addrs.getJSONArray("public");
String[] addresses = new String[arr.length()];
for( int i=0; i= 'a' && c <= 'z' ) {
if( last == '-' && !str.toString().endsWith("-") ) {
str.append('-');
}
str.append(c);
}
last = c;
}
if( name.length() < 1 ) {
name = "a";
}
String test = name;
int idx = 1;
while( serverExists(test) && idx<1000000 ) {
test = name + "-" + (idx++);
}
return test;
}
private String validateName(String name, boolean safeName) throws InternalException, CloudException {
if( safeName ) {
name = name.toLowerCase().replaceAll(" ", "-");
}
if( name.length() > NAME_LIMIT ) {
name = name.substring(0,NAME_LIMIT);
}
StringBuilder str = new StringBuilder();
for( int i=0; i 0 || Character.isLetter(c) ) {
str.append(c);
}
}
}
else {
if( (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' ) {
if( str.length() > 0 || Character.isLetter(c) ) {
str.append(c);
}
}
}
}
if( str.length() < 1 ) {
return makeUpName(name);
}
name = str.toString();
while( !Character.isLetterOrDigit(name.charAt(name.length()-1)) ) {
if( name.length() < 2 ) {
return makeUpName(name);
}
name = name.substring(0, name.length()-1);
}
if( serverExists(name) ) {
return makeUpName(name);
}
return name;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy