package dmg.cells.nucleus ; import com.google.common.base.Stopwatch; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.InterruptedIOException; import java.io.Reader; import java.io.Serializable; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.SortedSet; import java.util.Stack; import java.util.StringTokenizer; import java.util.TreeSet; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import dmg.cells.network.PingMessage; import dmg.util.BufferedLineWriter; import dmg.util.CommandEvaluationException; import dmg.util.CommandException; import dmg.util.CommandExitException; import dmg.util.CommandInterpreter; import dmg.util.CommandPanicException; import dmg.util.CommandSyntaxException; import dmg.util.CommandThrowableException; import dmg.util.Exceptions; import dmg.util.Formats; import dmg.util.PropertiesBackedReplaceable; import dmg.util.Replaceable; import dmg.util.ReplaceableBackedProperties; import dmg.util.Slf4jErrorWriter; import dmg.util.Slf4jInfoWriter; import dmg.util.command.Argument; import dmg.util.command.Command; import dmg.util.command.CommandLine; import dmg.util.command.DelayedCommand; import dmg.util.command.Option; import org.dcache.util.Args; /** * * * @author Patrick Fuhrmann * @version 0.1, 15 Feb 1998 */ public class CellShell extends CommandInterpreter implements Replaceable { private static final Logger _log = LoggerFactory.getLogger(CellShell.class); private static final Logger _logNucleus = LoggerFactory.getLogger(CellNucleus.class); enum ErrorAction { SHUTDOWN, EXIT, CONTINUE } private final CellNucleus _nucleus ; private StringBuilder _contextString; private String _contextName; private String _contextDelimiter; private StringBuilder _envString; private String _envName; private String _envDelimiter; private int _helpMode = 1 ; private int _errorCode; private String _errorMsg; private ErrorAction _doOnError = ErrorAction.CONTINUE; private final Map<String, Object> _environment = new ConcurrentHashMap<>(); private CommandInterpreter _externalInterpreter; private ImmutableList<String> _argumentVector = ImmutableList.of(); public CellShell( CellNucleus nucleus ){ _nucleus = nucleus ; try { objectCommand( "exec context shellProfile" ) ; } catch (CommandExitException e) { } } public CellShell(CellNucleus nucleus, CommandInterpreter interpreter) { this(nucleus); _externalInterpreter = interpreter; } /** * Returns the environment of the shell. * * The map is backed by the shell's environment. Any modification * to the map changes the shell environment and any change in the * shell environment is reflected in the map. */ public Map<String,Object> environment() { return _environment; } @Override public String getReplacement(String name) { Object o = getDictionaryEntry(name); return (o == null) ? null : o.toString(); } private static long __sequenceNumber = 1000000L ; private static synchronized long nextSequenceNumber(){ return __sequenceNumber ++ ; } public Object getDictionaryEntry( String name ){ switch (name) { case "rc": return String.valueOf(_errorCode); case "rmsg": return (_errorMsg == null ? "(0)" : _errorMsg); case "thisDomain": return _nucleus.getCellDomainName(); case "thisCell": return _nucleus.getCellName(); case "nextSequenceNumber": return String.valueOf(nextSequenceNumber()); case "thisHostname": try { String xname = InetAddress.getLocalHost().getHostName(); return new StringTokenizer(xname, ".").nextToken(); } catch (UnknownHostException e) { return "UnknownHostname"; } case "thisFqHostname": try { return InetAddress.getLocalHost().getCanonicalHostName(); } catch (UnknownHostException e) { return "UnknownHostname"; } default: try { int position = Integer.parseInt(name); if (position >= 0 && position < _argumentVector.size()) { Object o = _argumentVector.get(position); if (o == null) { throw new IllegalArgumentException(""); } return o; } } catch (NumberFormatException e) { } Object o = _environment.get(name); if (o == null) { o = _nucleus.getDomainContext().get(name); } return o; } } private String prepareCommand( String string ){ // // replace the variables ${...} // String str = Formats.replaceKeywords( string , this ) ; if( _contextString != null ){ // // are we in the define context ... // if (!str.isEmpty() && str.equals(_contextDelimiter)){ _nucleus.getDomainContext(). put( _contextName , _contextString.toString() ) ; _contextString = null ; return null ; } _contextString.append( str ).append('\n'); return null ; }else if( _envString != null ){ // // are we in the define environment // if (!str.isEmpty() && str.equals(_envDelimiter)){ _environment.put( _envName , _envString.toString() ) ; _envString = null ; return null ; } _envString.append( str ).append('\n'); return null ; } return str ; } public Serializable objectCommand2(String strin) { String str; if( ( str = prepareCommand( strin ) ) == null ) { return ""; } try{ Args args = new Args(str); if (args.argc() == 0) { return ""; } Serializable o; if( _externalInterpreter != null ){ o = _externalInterpreter.command(args); }else{ o = command(args); } _errorCode = 0 ; _errorMsg = null ; if( o == null ) { return ""; } return o ; }catch( CommandException ce ){ _errorCode = ce.getErrorCode() ; _errorMsg = ce.getErrorMessage() ; return ce ; } } public Object objectCommand( String strin ) throws CommandExitException { String str; if( ( str = prepareCommand( strin ) ) == null ) { return ""; } try{ Args args = new Args(strin); if (args.argc() == 0) { return ""; } Object o; if( _externalInterpreter != null ){ o = _externalInterpreter.command(args) ; }else{ o = command(args) ; } _errorCode = 0 ; _errorMsg = null ; if( o == null ) { return ""; } return o ; }catch( CommandException ce ){ _errorCode = ce.getErrorCode() ; _errorMsg = ce.getErrorMessage() ; switch (_doOnError) { case SHUTDOWN: throw new CommandExitException(ce.toString(), 666); case EXIT: throw new CommandExitException(ce.getErrorMessage(), ce.getErrorCode()); } if( ce instanceof CommandSyntaxException ){ CommandSyntaxException cse = (CommandSyntaxException)ce ; StringBuilder sb = new StringBuilder() ; sb.append( "Syntax Error : " ). append( cse.getMessage() ) ; if( _helpMode == 1 ){ sb.append( "\nUse 'help' for more information\n" ) ; }else if( _helpMode == 2 ){ String help = cse.getHelpText() ; if( help != null ) { sb.append('\n').append(help).append('\n'); } } return sb.toString() ; }else if( ce instanceof CommandExitException ){ if( _externalInterpreter != null ){ _externalInterpreter = null ; return "external shell exited ... " ; }else{ throw (CommandExitException) ce ; } }else if( ce instanceof CommandThrowableException ){ CommandThrowableException cte = (CommandThrowableException)ce ; StringBuilder sb = new StringBuilder() ; sb.append( cte.getMessage()).append(" -> " ) ; Throwable t = cte.getTargetException() ; sb.append( t.getClass().getName()).append(" : ").append(t.getMessage()).append('\n') ; return sb.toString() ; }else if( ce instanceof CommandPanicException ){ CommandPanicException cpe = (CommandPanicException)ce ; StringBuilder sb = new StringBuilder() ; sb.append( "Panic : ").append(cpe.getMessage()).append('\n') ; Throwable t = cpe.getTargetException() ; sb.append( t.getClass().getName()).append(" : ").append(t.getMessage()).append('\n') ; return sb.toString() ; }else{ return "CommandException :"+ce.getMessage() ; } } } @Override public String command( String c ) throws CommandExitException { StringTokenizer st = new StringTokenizer( c , "\n" ) ; StringBuilder sb = new StringBuilder(); while (st.hasMoreTokens()) { sb.append(commandLine(st.nextToken())); } return sb.toString() ; } private String commandLine( String c ) throws CommandExitException { if( _contextString != null ){ _contextString.append( c ).append('\n'); return "" ; }else { return super.command(c); } } //////////////////////////////////////////////////////////// // // version // @Command(name = "version", hint = "query jar file metadata", description = "Information about the implementation-title, -vendor " + "and -version, as described within some jar. The jar file " + "is the one that provides some specific Java package. If " + "the jar file implementation-vendor is 'dCache.org' then the " + "implementation-version is the dCache version.") public class VersionCommand implements Callable<Serializable> { @Argument(required = false, usage = "The package used to select the jar file.") String packageName="dmg.cells.nucleus"; @Override public Serializable call() { Package p = Package.getPackage(packageName); StringBuilder sb = new StringBuilder(); if( p != null ){ String tmp = p.getImplementationTitle(); sb.append("ImplementationTitle: ").append(tmp==null?"(Unknown)":tmp).append('\n'); tmp = p.getImplementationVendor(); sb.append("ImplementationVendor: ").append(tmp==null?"(Unknown)":tmp).append('\n'); tmp = p.getImplementationVersion(); sb.append("ImplementationVersion: ").append(tmp==null?"(Unknown)":tmp).append('\n'); }else{ sb.append("No information found"); } return sb.toString() ; } } //////////////////////////////////////////////////////////// // // getroutes, getcelltunnelinfos, getcellinfos // @Command(name = "getroutes", hint = "list all routes", description = "List all message routes available in " + "this domain. The returned information " + "comprises of the target cell name, target domain name, " + "gateway for this route and the route type (such as " + "default, alias, domain, topic, etc).") public class GetroutesCommand implements Callable<CellRoute[]> { @Override public CellRoute[] call() throws Exception { return _nucleus.getRoutingList() ; } } public CellTunnelInfo[] ac_getcelltunnelinfos( Args args ){ List<CellTunnelInfo> cellTunnelInfos = _nucleus.getCellTunnelInfos(); return cellTunnelInfos.toArray(new CellTunnelInfo[cellTunnelInfos.size()]); } @Command(name = "getcellinfo", hint = "display cell information", description = "Shows a brief information on a specified cell. " + "This information consist of the cell name, " + "the state of the cell " + "(a cell can be in one of these following states: Initial, " + "Active, Removing, Dead and Unknown state which are " + "denoted by I, A, R, D and U respectively), " + "the event queue size, thread count, " + "the class the cell belong to and, lastly, a short cell " + "specific information.") public class GetcellinfoCommand implements Callable<CellInfo> { @Argument(usage = "The cell name") String cellName; @Override public CellInfo call() throws Exception { CellInfo info = _nucleus.getCellInfo(cellName); if(info == null ) { throw new CommandException(68, "not found : " + cellName); } return info; } } @Command(name = "getcellinfos", hint = "get information on all cells", description = "Display a summarised information of all cells " + "in this domain. This " + "information (starting from left to right) comprises of " + "the cell name, cell state " + "(a cell can be in one of these following states: Initial, " + "Active, Removing, Dead and Unknown state which are " + "denoted by I, A, R, D and U respectively), " + "the event queue size, thread count, " + "cell class and lastly a short cell specific information.") public class GetcellinfosCommand implements Callable<CellInfo[]> { @Override public CellInfo[] call() throws Exception { List<String> names = _nucleus.getCellNames(); List<CellInfo> infoList = new ArrayList<>(names.size()); for(String name : names) { CellInfo info = _nucleus.getCellInfo(name); if(info != null) { infoList.add(info); } } return infoList.toArray(new CellInfo[infoList.size()]); } } @Command(name = "getcontext", hint = "list all contexts", description = "Returns a " + "list of all the contexts in your current domain. " + "When a context name (within the current domain) is specified, " + "it will return the content of that context.") public class GetcontextCommand implements Callable<Serializable> { @Argument(required = false, usage = "The context name") String contextName; @Override public Serializable call() throws Exception { if (contextName == null) { return _nucleus.getDomainContext().keySet().toArray(); }else{ Object o = _nucleus.getDomainContext( contextName ) ; if( o == null ) { throw new CommandException("Context not found : " + contextName); } return (Serializable) o; } } } //////////////////////////////////////////////////////////// // // waitfor cell/domain/context // public static final String hh_waitfor= "context|cell|domain <objectName> [<domain>] [-i=<checkInterval>] [-wait=<maxTime>]" ; public static final String fh_waitfor = "waitfor [options] context <contextName> [<domainName]\n" + "waitfor [options] cell <cellPath>\n" + "waitfor [options] domain <domainName>\n"+ " Options : -i=<probeInterval -wait=<maxWaitSeconds>\n" ; public String ac_waitfor_$_2_3( Args args ) throws CommandException{ int waitTime = 0 ; int check = 1 ; for( int i = 0 ; i < args.optc() ; i ++ ){ if( args.optv(i).startsWith("-i=") ) { check = Integer.parseInt(args.optv(i).substring(3)); } else if( args.optv(i).startsWith("-wait=") ) { waitTime = Integer.parseInt(args.optv(i).substring(6)); } } if( waitTime < 0 ) { waitTime = 0; } String what = args.argv(0) ; String name = args.argv(1) ; switch (what) { case "cell": return _waitForCell(name, waitTime, check, null); case "domain": return _waitForCell("System@" + name, waitTime, check, null); case "context": if (args.argc() > 2) { return _waitForCell("System@" + args.argv(2), waitTime, check, "test context " + name); } else { return _waitForContext(name, waitTime, check); } } throw new CommandException( "Unknown Observable : "+what ) ; } private String _waitForContext( String contextName , int waitTime , int check ) throws CommandException { if( check <= 0 ) { check = 1; } long finish = System.currentTimeMillis() + ( waitTime * 1000 ) ; while( true ){ Object o = _nucleus.getDomainContext( contextName ) ; if( o != null ) { break; } if( ( waitTime == 0 ) || ( finish > System.currentTimeMillis() ) ){ try{ Thread.sleep(((long)check)*1000) ; } catch( InterruptedException ie ){ throw new CommandException( 2 , "Command Was interrupted" ) ; } continue ; } throw new CommandException( 1 , "Command Timed Out" ) ; } return "" ; } private String _waitForCell( String cellName , int waitTime , int check , String command ) throws CommandException { if( check <= 4 ) { check = 5; } CellPath destination = new CellPath( cellName ) ; long finish = System.currentTimeMillis() + ( waitTime * 1000 ) ; CellMessage answer; Serializable message = (command == null) ? new PingMessage() : command; Object o; boolean noRoute; while( true ){ noRoute = false ; answer = null ; try{ _log.warn( "waitForCell : Sending request" ) ; answer = _nucleus.sendAndWait(new CellMessage(destination , message), ((long) check) * 1000); _log.warn( "waitForCell : got "+answer ) ; } catch (NoRouteToCellException e) { noRoute = true ; } catch (ExecutionException ignored) { } catch (InterruptedException e) { throw new CommandException(66, "sendAndWait problem : " + e, e); } if( ( answer != null ) && ( ( o = answer.getMessageObject() ) != null ) && ( ( o instanceof PingMessage ) || (o instanceof String) ) ) { break; } if( ( waitTime == 0 ) || ( finish > System.currentTimeMillis() ) ){ // // not to waste cpu time, we should distinquish between // between timeout and NoRouteToCellException // if( ( ! noRoute ) && ( answer == null ) ) { continue; } // // this answer was to fast to try it again, so we wait // try{ Thread.sleep(((long)check)*1000) ; } catch( InterruptedException ie ){ throw new CommandException( 2 , "Command Was interrupted" ) ; } continue ; } throw new CommandException( 1 , "Command Timed Out" ) ; } return "" ; } //////////////////////////////////////////////////////////// // // route // public static final String fh_route = " Syntax : route # show all routes\n"+ " route add|delete [options] <source> <destination>\n" ; public String ac_route_$_0( Args args ){ return _nucleus.getRoutingTable().toString() ; } public static final String hh_route_add = "-options <source> <destination>" ; public static final String fh_route_add = fh_route ; public String ac_route_add_$_1_2(Args args) throws IllegalArgumentException { _nucleus.routeAdd( new CellRoute( args ) ); return "Done\n" ; } public static final String hh_route_delete = "-options <source> <destination>" ; public static final String fh_route_delete = fh_route ; public String ac_route_delete_$_1_2(Args args) throws IllegalArgumentException { _nucleus.routeDelete(new CellRoute(args)); return "Done\n" ; } public static final String hh_route_find = "<address>" ; public String ac_route_find_$_1( Args args ) throws IllegalArgumentException { CellAddressCore addr = new CellAddressCore( args.argv(0) ) ; CellRoute route = _nucleus.routeFind( addr ); if( route != null ) { return route.toString() + '\n'; } else { return "No Route To cell : " + addr + '\n'; } } //////////////////////////////////////////////////////////// // // ps -af <cellname> // @Command(name = "ps", hint = "list cells in the domain", description = "List all cells within the current domain. " + "The option \'-f\' provides information about the " + "cells in the domain. This information comprises " + "of the cell name, the cell current state (a cell " + "can be in one of these following states: Initial, " + "Active, Removing, Dead and Unknown state which " + "are denoted by I, A, R, D and U respectively), " + "the number of message queues, the thread count, " + "the class name of the cell and lastly, a short " + "description of the cell itself." + "\n\n" + "When a particular cell is specify, a summarised " + "information on the cell is returned. With the option " + "'-f', all information about the cell will be return in a " + "comprehensive and detailed manner.") public class PsCommand implements Callable<String> { @Argument(usage = "specify a cell or list of cell names", required = false) String[] cellName; @Option(name="f", usage = "display with the full attributes" ) boolean full; @Override public String call() { StringBuilder sb = new StringBuilder() ; if( cellName == null ){ List<String> list = _nucleus.getCellNames(); if (full) { for (String name: list) { CellInfo info = _nucleus.getCellInfo(name); if (info == null){ sb.append(name).append(" (defunc)\n" ) ; } else { sb.append(info).append('\n') ; } } } else { for (String name: list) { sb.append(name).append('\n'); } } } else { for (String aCellName : cellName) { CellInfo info = _nucleus.getCellInfo(aCellName); if (info == null) { sb.append(aCellName).append(" Not found\n"); continue; } if (full) { sb.append("-- Info --\n"); sb.append(" Cell : ").append(info.getCellName()).append('@').append(info.getDomainName()).append('\n'); sb.append(" Class : ").append(info.getCellClass()).append('\n'); sb.append(" State : ").append(info.getStateName()).append('\n'); sb.append(" Queue length : ").append(info.getEventQueueSize()).append('\n'); sb.append(" Queue time : ").append(info.getExpectedQueueTime()).append(" ms \n"); CellVersion version = info.getCellVersion(); if (version != null) { sb.append(" Version : ").append(version).append('\n'); } sb.append("-- Threads --\n"); Thread[] threads = _nucleus.getThreads(aCellName); for (int j = 0; (j < threads.length) && (threads[j] != null); j++) { boolean isAlive = threads[j].isAlive(); sb.append(CellInfo.f(threads[j].getName(), 20)) .append(CellInfo .f(String.valueOf(threads[j].getPriority()), 2)) .append(isAlive ? " Alive" : " Dead") .append('\n'); } sb.append("-- Private Infos --\n"); } sb.append(info.getPrivatInfo()).append('\n'); } } return sb.toString() ; } } //////////////////////////////////////////////////////////// // // kill // @Command(name = "kill", hint = "kill a cell", description = "Kills the named CELL. If CELL is 'System' then, " + "in addition to killing the System cell, the domain " + "shutdown sequence is triggered. This will result " + "in the JVM process ending.") public class KillCommand implements Callable<Reply> { @Argument(index = 0, usage = "specify the cell name") String cellName; @Override public Reply call() throws IllegalArgumentException, InterruptedException { // The killing of a cell requires deliver of a message to the targeted // cell. If CellShell is running in the targeted shell then the call // to _nucleus.join will never return unless we free up the // message-processing thread by returning from this method. We return a // delayed reply to achieve this while also not delivering the reply // until after the cell has terminated. final DelayedReply future = new DelayedReply(); Thread thread = new Thread("kill "+cellName+" command") { @Override public void run() { Serializable response = ""; try { try { _nucleus.kill(cellName).get(); } catch (ExecutionException e) { response = e.getCause(); } future.reply(response); } catch (InterruptedException e) { // Do nothing, dCache is shutting down. } } }; thread.setDaemon(true); thread.start(); return future; } } @Command(name = "send", hint = "send message to cell", description = "Sends MESSAGE to ADDRESS.") class SendCommand extends DelayedReply implements Callable<Serializable>, CellMessageAnswerable { @Option(name = "w", usage = "wait 10 seconds for answer to arrive") boolean wait; @Option(name = "nolocal", usage = "don't deliver locally") boolean nolocal; @Option(name = "noremote", usage = "don't deliver remotely") boolean noremote; @Argument(index = 0, metaVar = "address", usage = "Colon separated path of cell addresses.") CellPath address; @Argument(index = 1, metaVar = "message") String message; @Override public Serializable call() { CellMessage msg = new CellMessage(address, message); if (wait) { _nucleus.sendMessage(msg, !nolocal, !noremote, true, this, MoreExecutors.directExecutor(), 10000); return this; } else { _nucleus.sendMessage(msg, !nolocal, !noremote, true); return "UOID = " + msg.getUOID(); } } @Override public void answerArrived(CellMessage request, CellMessage answer) { Serializable obj = answer.getMessageObject(); reply(obj == null ? answer : obj); } @Override public void exceptionArrived(CellMessage request, Exception exception) { reply(exception); } @Override public void answerTimedOut(CellMessage request) { reply("Timeout... "); } } @Command(name = "traceroute", hint = "print the domains messages take", description = "Prints the cell paths a cell message follows in both the outbound and inbound direction.") class TracerouteCommand extends DelayedReply implements Callable<Serializable>, CellMessageAnswerable { @Argument(metaVar = "address", usage = "Colon separated path of cell addresses.") CellPath address; @Option(name = "nolocal", usage = "don't deliver locally") boolean nolocal; @Option(name = "noremote", usage = "don't deliver remotely") boolean noremote; @Override public Serializable call() { CellMessage msg = new CellMessage(address, new PingMessage()); _nucleus.sendMessage(msg, !nolocal, !noremote, true, this, MoreExecutors.directExecutor(), 10000); return this; } @Override public void answerArrived(CellMessage request, CellMessage answer) { reply(((PingMessage) answer.getMessageObject()).getOutboundPath() + " -> " + answer.getSourcePath()); } @Override public void exceptionArrived(CellMessage request, Exception exception) { reply(exception); } @Override public void answerTimedOut(CellMessage request) { reply("Timeout... "); } } //////////////////////////////////////////////////////////// // // sleep // @Command(name = "sleep", hint = "wait for a period of time", description = "Wait for the specified duration of time then " + "return 'Ready'.") public class SleepCommand extends DelayedCommand<String> { @Argument(metaVar = "seconds", usage = "The amount of time to be asleep.") int sleepTime; @Override public String execute() throws InterruptedException { Thread.sleep(sleepTime*1000); return "Ready\n"; } } @Command(name = "ping", hint = "send a message and wait for the reply", description = "A ping message of a default or specified size is send to " + "the destination cell. The message is processed and a reply is " + "send back to the sender. This procedure is repeated based on the " + "number of iterations specified. A timeout message is returned as " + "a result of the termination of the command. This happens if the " + "timeout duration elapsed before the command finish its execution. " + "On a successful run, the number of pings with the time taken will " + "be printed.\n\n" + "The ping command can be use to test a connection to a cell, " + "check the latency of the message system, and to verify " + "if a cell is up and running.") public class PingCommand extends DelayedReply implements Callable<PingCommand> { @Argument(index = 0, usage = "Name of the cell to be pinged.") CellPath destinationCell; @Argument(index = 1, required = false, metaVar = "bytes", usage = "The size of the message to be sent.") int messageSize; @Argument(index = 2, required = false, usage = "The number of times the cell should be pinged.") int packets = 1; @Option(name = "timeout", valueSpec = "MILLISECONDS", usage = "The duration of time that ping waits for a reply.") int timeout = 1000; private int count; private final Stopwatch sw = Stopwatch.createUnstarted(); @Override public PingCommand call() throws Exception { sw.start(); ping(); return this; } private void ping() { if (count < packets) { count++; _nucleus.sendMessage(new CellMessage(destinationCell, new PingMessage(messageSize)), true, true, true, new CellMessageAnswerable() { @Override public void answerArrived(CellMessage request, CellMessage answer) { ping(); } @Override public void exceptionArrived(CellMessage request, Exception exception) { reply(exception); } @Override public void answerTimedOut(CellMessage request) { reply("Timeout"); } }, MoreExecutors.directExecutor(), timeout); } else { reply(packets + " pings in " + sw); } } } //////////////////////////////////////////////////////////// // // create // @Command(name = "create", hint = "create a cell", description = "Create a cell within the current dCache domain. " + "To create a cell requires, the cell name and the class " + "it belongs. Depending on the class type of the cell, " + "some necessary configuration might be required in other " + "to instantiate the cell. This can be supply through the " + "cellArg argument. If the configuration is more than one, " + "since cellArg is a single argument, the configuration " + "settings must be inside a quotation mark.") public class CreateCommand implements Callable<String> { @Argument(index = 0, usage = "Fully qualified name of the cell class. For example, " + "creating a topo cell requires specifying the following " + "class name: dmg.cells.network.TopoCell") String className; @Argument(index = 1, usage = "Name of the cell to be created.") String cellName; @Argument(index = 2, required = false, usage = "Arguments passed to the cell. The supported " + "arguments are cell specific.") String cellArg = ""; @Option(name = "async") boolean isAsync; @Override public String call() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassCastException, CommandException, InterruptedException { Constructor<? extends CellAdapter> constructor = Class.forName(className).asSubclass(CellAdapter.class).getConstructor(String.class, String.class); try { CellAdapter cell = constructor.newInstance(cellName, cellArg); if (cell instanceof EnvironmentAware) { ((EnvironmentAware) cell).setEnvironment(Collections.unmodifiableMap(_environment)); } ListenableFuture<Void> startup = cell.start(); if (!isAsync) { startup.get(); } else { Futures.addCallback(startup, new FutureCallback<Void>() { @Override public void onSuccess(@Nullable Void result) { _log.info("created: {}", cellName); } @Override public void onFailure(Throwable t) { _log.error("failed create {}: {}", cellName, t.toString()); } }); } return "created : " + cell; } catch (CancellationException e) { throw new CommandThrowableException("Startup of " + cellName + " was cancelled.", e); } catch (InvocationTargetException e) { Throwables.throwIfUnchecked(e.getCause()); throw new RuntimeException(e.getCause()); } catch (ExecutionException e) { Throwables.throwIfInstanceOf(e.getCause(), CommandException.class); throw new CommandThrowableException(e.getCause().getMessage(), e.getCause()); } } } //////////////////////////////////////////////////////////// // // this and that // @Command(name = "onerror", hint = "set error action", description = "Defines how the command interpreter reacts to processing errors.") class OnErrorCommand implements Callable<String> { @Argument(valueSpec = "shutdown|exit|continue", usage = "shutdown:\n" + "\tterminate dCache domain.\n" + "exit:\n" + "\tterminate interpreter.\n" + "continue:\n" + "\tignore error.") ErrorAction action; @Override public String call() { _doOnError = action; return ""; } } @Command(name = "show onerror", hint = "show current error action", description = "Shows how the command interpreter reacts to errors. The action can " + "be set using the onerror command.") class ShowOnErrorCommand implements Callable<String> { @Override public String call() { return _doOnError.toString().toLowerCase(); } } private static final int PRINT_CELL = 1; private static final int PRINT_ERROR_CELL = 2; private static final int PRINT_NUCLEUS = 4; private static final int PRINT_ERROR_NUCLEUS = 8; private static final int PRINT_FATAL = 0x10; public static final String hh_say = "<things to echo ...> [-level=<level>]" ; public static final String fh_say = "<things to echo ...> [-level=<level>]\n"+ " Levels :\n" + " say,esay,fsay\n"+ " PRINT_CELL = 1\n" + " PRINT_ERROR_CELL = 2\n" + " PRINT_NUCLEUS = 4\n" + " PRINT_ERROR_NUCLEUS = 8\n" + " PRINT_FATAL = 0x10" ; public String ac_say_$_1_99( Args args ) { StringBuilder sb = new StringBuilder() ; for( int i = 0 ; i < args.argc() ; i++ ) { sb.append(args.argv(i)).append(' '); } String msg = sb.toString() ; String levelString = args.getOpt("level") ; if( ( levelString != null ) && (!levelString.isEmpty()) ){ switch (levelString) { case "say": _log.info(msg); break; case "esay": _log.warn(msg); break; case "fsay": _log.error(msg); break; default: try { int level = Integer.parseInt(levelString); if ((level & PRINT_CELL) != 0) { _log.info(msg); } if ((level & PRINT_ERROR_CELL) != 0) { _log.warn(msg); } if ((level & PRINT_FATAL) != 0) { _log.error(msg); } if ((level & PRINT_NUCLEUS) != 0) { _logNucleus.info(msg); } if ((level & PRINT_ERROR_NUCLEUS) != 0) { _logNucleus.warn(msg); } } catch (NumberFormatException e) { throw new IllegalArgumentException("Illegal Level string: " + levelString); } break; } } return msg ; } public static final String hh_echo = "<things to echo ...>" ; public String ac_echo_$_1_99( Args args ){ StringBuilder sb = new StringBuilder() ; for( int i = 0 ; i < args.argc() ; i++ ) { sb.append(args.argv(i)).append(' '); } return sb.toString() ; } public static final String hh_show_error = " # shows last errorCode and Message "; public String ac_show_error( Args args ){ if( _errorCode == 0 ) { return "No Error found"; } return "errorCode="+_errorCode+"; Msg = "+ (_errorMsg==null?"None":_errorMsg) ; } public static final String hh_set_helpmode = "none|full" ; public String ac_set_helpmode_$_1( Args args ) throws CommandException { String mode = args.argv(0) ; switch (mode) { case "none": _helpMode = 0; break; case "full": _helpMode = 2; break; default: throw new CommandException(22, "Illegal Help Mode : " + mode); } return "" ; } public String ac_id( Args args ){ return _nucleus.getCellDomainName() + '\n'; } @Command(name = "check", hint = "check if variables are defined", description = "Determine if all variables are defined. " + "An error is return if at least one of the variables " + "is not defined.") public class CheckCommand implements Callable<String> { @Argument(usage = "One or more variable names to check.") String[] varName; @Option(name = "strong", usage = "This returns an error if any of the variables " + "contain only whitespace.") boolean strong; @Override public String call() throws CommandException { Object value; for (String name : varName) { if ((value = _environment.get(name)) == null) { value = _nucleus.getDomainContext().get(name); } if (value == null) { throw new CommandException(1, "variable is not defined : " + name); } if (strong) { String strValue = value.toString(); if (strValue.trim().isEmpty()) { throw new CommandException(2, "variable is defined but empty : " + name); } } } return "" ; } } public static final String fh_import_context = " import context|env [options] <variableName>\n" + " options :\n"+ " -c : don't overwrite\n"+ " -source=env|context : only check the specifed\n"+ " source for the variableName\n"+ " -nr : don't run the variable resolver\n"+ "\n"+ " The source is interpreted as a set of lines separated by\n"+ " newlines. Each line is assumed to contain a key value pair\n"+ " separated by the '=' sign.\n"+ " The context/environment variables are set according to\n"+ " the assignment.\n" ; public static final String fh_import_env = fh_import_context ; public static final String hh_import_context = "[-source=context|env] [-nr]"+ "<contextVariableName>" ; public static final String hh_import_env = "[-source=context|env] [-nr]"+ "<environmentVariableName>" ; public String ac_import_context_$_1( Args args )throws CommandException { return imprt_dict( args , _nucleus.getDomainContext() ) ; } public String ac_import_env_$_1( Args args )throws CommandException { return imprt_dict( args , _environment ) ; } private String imprt_dict(Args args, Map<String,Object> dict) throws CommandException { String varName = args.argv(0); boolean opt_overwrite = !args.hasOption("c"); boolean resolve = !args.hasOption( "nr" ); String src = args.getOpt("source"); Object input; if (src == null) { input = _environment.get(varName); if (input == null) { input = _nucleus.getDomainContext().get(varName); } } else if (src.equals("env")) { input = _environment.get(varName); } else if (src.equals("context")) { input = _nucleus.getDomainContext().get(varName); } else { throw new CommandException("Invalid value for -source=" + src); } if (input == null) { throw new CommandException("Variable is not defined: " + varName); } try { Properties properties = new ReplaceableBackedProperties(this); properties.load(new StringReader(input.toString())); for (String key: properties.stringPropertyNames()) { if (opt_overwrite || (dict.get(key) == null)) { String value = properties.getProperty(key); int length = value.length(); if (length > 1 && value.charAt(0) == '"' && value.charAt(length - 1) == '"') { value = value.substring(1, length - 1); } if (resolve) { value = Formats.replaceKeywords(value, new PropertiesBackedReplaceable(properties)); } dict.put(key, value); } } } catch (IllegalArgumentException | IOException e) { throw new CommandException(3, "Failed to read " + varName + ": " + e); } return ""; } public static final String fh_set_context = "set context|env [options] <variableName> <value>\n"+ " options :\n"+ " -c : do not overwrite the variable if it's already set\n"+ " -s : run the value through the interpreter and\n"+ " convert '\\n' to a real newline" ; public static final String fh_set_env = fh_set_context ; public static final String hh_set_context = "[-c][-s] <contextName> <value>" ; public static final String hh_set_env = "[-c][-s] <environmentName> <value>" ; public String ac_set_context_$_2( Args args )throws CommandException{ return set_dict( args , _nucleus.getDomainContext() ) ; } public String ac_set_env_$_2( Args args )throws CommandException{ return set_dict( args , _environment ) ; } private String set_dict(Args args, Map<String,Object> dict) throws CommandException { String name = args.argv(0) ; String value = args.argv(1) ; boolean opt_overwrite = !args.hasOption("c") ; boolean opt_interpreter = args.hasOption("s") ; if( ( ! opt_overwrite ) && ( dict.get( name ) != null ) ) { throw new CommandEvaluationException(1, "Variable " + name + " is already set and can't be overwritten due to '-c'"); } if( opt_interpreter ){ final int I_IDLE = 0 ; final int I_BS = 1 ; int state = I_IDLE ; StringBuilder sb = new StringBuilder(); for( int i = 0 ; i < value.length() ; i++ ){ char c = value.charAt(i) ; switch( state ){ case I_IDLE : if( c == '\\' ){ state = I_BS ; }else{ sb.append( c ) ; } break ; case I_BS : if( c == 'n' ){ state = I_IDLE ; sb.append( '\n' ) ; }else{ sb.append( '\\' ) ; sb.append( c ) ; } break ; } } value = sb.toString() ; } dict.put( name , value ) ; return "" ; } //////////////////////////////////////////////////////////// // // unsetting the context/environment // public static final String hh_unset_context="<contextName>" ; public static final String hh_unset_env ="<environmentName>" ; public String ac_unset_context_$_1( Args args )throws CommandException { return unset_dict( args , _nucleus.getDomainContext() ) ; } public String ac_unset_env_$_1( Args args )throws CommandException { return unset_dict( args , _environment ) ; } private String unset_dict(Args args, Map<String,Object> dict) throws CommandException { String name = args.argv(0) ; Object o = dict.remove( name ) ; if( o == null ){ throw new CommandException ( "Not found : "+name ) ; }else{ return name + '<' + o.getClass().getName() + "> removed\n" ; } } //////////////////////////////////////////////////////////// // // displaying the context/environment variables // public static final String hh_ls = "[-l] [-ll] [-e] [-list]" ; public static final String fh_ls = " ls [options]\n"+ " Prints context/environment\n"+ " Options\n"+ " -l adds class name\n"+ " -ll adds first 40 chars of content\n"+ " -e list environment instead of context\n"+ " -list prints simple list instead of formatted one\n"+ "\n"; public static final String hh_show_context = "[<contextName>]" ; public static final String hh_show_env = "[<environmentName>]" ; public static final String hh_test_context = "[<contextName>]" ; public static final String hh_test_env = "[<environmentName>]" ; public String ac_ls_$_0_1( Args args ) throws CommandException { return ls_dict( args , args.hasOption("e") ? _environment : _nucleus.getDomainContext() ) ; } public String ac_show_context_$_0_1( Args args ) throws CommandException { return show_dict( args , _nucleus.getDomainContext() ) ; } public String ac_show_env_$_0_1( Args args ) throws CommandException { return show_dict( args , _environment ) ; } public String ac_test_context_$_0_1( Args args ) throws CommandException { return test_dict(args, _nucleus.getDomainContext()) ; } public String ac_test_env_$_0_1( Args args ) throws CommandException { return test_dict(args, _environment) ; } private String test_dict(Args args, Map<String,Object> dict) throws CommandException { String name = args.argv(0) ; if( dict.get( name ) == null ){ throw new CommandException( 66 , "not found : "+name ); }return "" ; } private String show_dict(Args args, Map<String,Object> dict) throws CommandException { StringBuilder sb = new StringBuilder(); if( args.argc() == 0 ){ for (Map.Entry<String,Object> e: dict.entrySet()) { String name = e.getKey(); Object o = e.getValue(); if( o instanceof String ){ sb.append(name).append('=') ; String line = (String)o ; int len = line.length() ; len = len > 40 ? 40 : len ; for( int i = 0 ; i < len ; i++ ) { sb.append(line.charAt(i) == '\n' ? '$' : line.charAt(i)); } if( len == 40 ) { sb.append("...\n"); } else { sb.append('\n'); } }else { sb.append(name).append("=<").append(o.getClass().getName()) .append(">\n"); } } }else{ String name = args.argv(0) ; Object o = dict.get( name ) ; if( o == null ) { throw new CommandException(23, "Context name " + name + " not found"); } sb.append(o) ; } return sb.toString() ; } private String ls_dict(Args args, Map<String,Object> dict) throws CommandException { StringBuilder sb = new StringBuilder(); if( args.argc() == 0 ){ int maxLength = 0 ; SortedSet<String> set = new TreeSet<>(); for (String name: dict.keySet()) { maxLength = Math.max( maxLength , name.length() ) ; set.add(name); } boolean detail = args.hasOption("l") ; boolean moreDetail = args.hasOption("ll") ; if( moreDetail ) { detail = true; } boolean list = args.hasOption("list") ; for (String name : set) { sb.append(name); if (detail) { sb.append(" "); if (!list) { int diff = maxLength - name.length(); for (int i = 0; i < diff; i++) { sb.append('.'); } } Object o = dict.get(name); sb.append(" ").append(o.getClass().getName()); if (moreDetail) { sb.append("\n "); String line = o.toString(); int len = line.length(); len = len > 40 ? 40 : len; for (int i = 0; i < len; i++) { sb.append(line.charAt(i) == '\n' ? '$' : line .charAt(i)); } if (len == 40) { sb.append("..."); } } } sb.append('\n'); } }else{ throw new CommandSyntaxException("Not yet supported"); } return sb.toString() ; } public static final String fh_test = "test <kind> <target>\n\n" + " Check whether <target>, of type <kind>, is available in the current environment.\n" + " If <target> is present then the return-code is zero, if not then a non-zero\n" + " return-code is returned.\n\n" + " Possible invocations are:\n" + " -i <cell> test if <cell> is running,\n" + " -e <file> test if <file> exists,\n" + " -f <file> test if <file> exists and is a normal file,\n" + " -d <file> test if <file> exists and is a directory"; public static final String hh_test = "-i <cell> | -e <file> | -f <file> | -d <file>"; public String ac_test_$_1(Args args) throws CommandEvaluationException { Tester tester = testerForArgs(args); if( !tester.test()){ throw new CommandEvaluationException(1, tester.getMessage()); } return ""; } Tester testerForArgs( Args args) { if( args.argc() != 1) { throw new IllegalArgumentException( "Expecting exactly one argument"); } if( args.hasOption("i")) { return new CellRunningTester(args); } else if( args.hasOption( "e")) { return new FileExistsTester(args); } else if( args.hasOption( "f")) { return new FileIsNormalTester(args); } else if( args.hasOption( "d")) { return new FileIsDirectoryTester(args); } else { throw new IllegalArgumentException( "Expecting either -cell or -file"); } } public static final String fh_exec = "exec [<options>] <url> [<args>]\n" + "exec context [<options>] <contextName> [<args>]\n" + "exec env [<options>] <envName> [<args>]\n"+ "\n"+ " Executes the content of an env or context variable or the\n" + " resource identified by the URL.\n"+ " -shell : opens a new shell for the execution\n"+ " -nooutput : discard the output of the executed commands\n"+ " -loop=<variableContextName> : \n"+ " Executes the block for each line in <varContextName> as arg\n"+ " -ifok[=<varName>] : run the context/env ONLY if the \n"+ " specified value of <varName> is '0'\n"+ " The default <varName> is 'rc'\n"+ " -ifnotok[=<varName>] : negation of -ifok\n\n"; public static final String hh_exec = "[-shell] [-nooutput] [-loop=<variable>] [-ifok[=<variable>]|-ifnotok[=<variable>}] <url> [<args>]"; public String ac_exec_$_1_99(Args args) throws CommandException { try { URI uri = new URI(args.argv(0)); args.shift(); return run_reader(uri, args); } catch (URISyntaxException e) { throw new CommandException(43 , e.getMessage()); } } public static final String fh_exec_env = fh_exec; public static final String hh_exec_env = "[-shell] [-nooutput] [-loop=<variable>] [-ifok[=<variable>]|-ifnotok[=<variable>}] <envName> [<args>]"; public String ac_exec_env_$_1_99(Args args) throws CommandException { try { URI uri = new URI("env", args.argv(0), null); args.shift(); return run_reader(uri, args); } catch (URISyntaxException e) { throw new CommandException(43, e.getMessage()); } } public static final String fh_exec_context = fh_exec; public static final String hh_exec_context = "[-shell] [-nooutput] [-loop=<variable>] [-ifok[=<variable>]|-ifnotok[=<variable>}] <contextName> [<args>]"; public String ac_exec_context_$_1_99(Args args) throws CommandException { try { URI uri = new URI("context", args.argv(0), null); args.shift(); return run_reader(uri, args); } catch (URISyntaxException e) { throw new CommandException(43 , e.getMessage()); } } private void println(Writer out, String s) throws IOException { if (!s.isEmpty()) { out.append(s); if (!s.isEmpty() && s.charAt(s.length() - 1) != '\n') { out.append('\n'); } } } public void execute(String source, Reader in, Args args) throws CommandExitException, IOException { try (Writer out = new BufferedLineWriter(new Slf4jInfoWriter(_log)); Writer err = new BufferedLineWriter(new Slf4jErrorWriter(_log))) { execute(source, in, out, err, args); } } public void execute(String source, Reader in, Writer out, Writer err, Args args) throws CommandExitException, IOException { ImmutableList<String> store = _argumentVector; int no = 1; try { _argumentVector = args.getArguments(); String line; StringBuilder sb = null; BufferedReader input = new BufferedReader(in); for (; (line = input.readLine()) != null; no = no + 1) { /* Skip empty and comment lines. */ String s = line.trim(); if (s.isEmpty() || s.charAt(0) == '#') { continue; } /* Handle line continuation. */ int len = line.length(); if (line.charAt(len - 1) == '\\') { if (sb == null) { sb = new StringBuilder(); } sb.append(line.substring(0, len - 1)).append(' '); continue; } else if (sb != null) { sb.append(line); line = sb.toString(); sb = null; } /* Execute command. */ Object answer = objectCommand2(line); if (answer instanceof DelayedReply) { answer = ((DelayedReply)answer).take(); } /* Process result. */ if (!(answer instanceof Throwable)) { println(out, answer.toString()); } else { Throwable error = (Throwable) answer; if (error instanceof CommandPanicException) { _log.error("Bug detected in dCache; please report this " + "to <support@dcache.org> with the following " + "information.", error); } if (_doOnError != ErrorAction.CONTINUE) { String msg = String.format("%s: line %d: %s", source, no, error.getMessage()); if (_doOnError == ErrorAction.SHUTDOWN) { throw new CommandExitException(msg, 666, error); } else if (error instanceof CommandException) { int rc = ((CommandException) error).getErrorCode(); throw new CommandExitException(msg, rc, error); } else { throw new CommandExitException(msg, 1, error); } } /* CommandEvaluationException does not generate * output since it is not really an error. Runtime * exceptions other than IllegalArgumentException * are logged. Other exceptions are printed to the * error output. */ if (error instanceof IllegalArgumentException) { String msg = String.format("%s: line %d: Illegal argument (%s)", source, no, error.getMessage()); println(err, msg); } else if (error instanceof RuntimeException) { _log.warn(error.toString(), error); } else if (!(error instanceof CommandEvaluationException)) { String msg = Exceptions.getMessageWithCauses(error); println(err, String.format("%s: line %d: Command failed (%s)", source, no, msg)); } } } } catch (InterruptedException e) { throw new CommandExitException(String.format("%s: line %d: interrupted", source, no)); } catch (IOException e) { throw new IOException(String.format("%s: line %d: %s", source, no, e.getMessage()), e); } catch (RuntimeException e) { throw new RuntimeException(String.format("%s: line %d: %s", source, no, e.toString()), e); } finally { _argumentVector = store; } } private String run_reader(URI uri, Args args) throws CommandException { String loopName = args.getOpt("loop"); String var; if ((var = args.getOpt("ifok")) != null) { if (var.isEmpty()) { if (_errorCode != 0) { return ""; } } else { Object x = getDictionaryEntry(var) ; if ((x == null) || (!x.toString().equals("0"))) { return ""; } } } if ((var = args.getOpt("ifnotok")) != null) { if (var.isEmpty()) { if (_errorCode == 0) { return ""; } } else { Object x = getDictionaryEntry(var) ; if ((x != null) && (x.toString().equals("0"))) { return ""; } } } try { StringWriter out = new StringWriter(); if (loopName == null) { CellShell shell = (args.hasOption("shell")) ? new CellShell(_nucleus) : this; try (Reader in = open(uri)) { shell.execute(uri.toString(), in, out, out, args); } } else { try (Reader loopReader = _nucleus .getDomainContextReader(loopName)) { BufferedReader reader = new BufferedReader(loopReader); String line; while ((line = reader.readLine()) != null) { CellShell shell = (args.hasOption("shell")) ? new CellShell(_nucleus) : this; try (Reader in = open(uri)) { shell.execute(uri.toString(), in, out, out, new Args(line)); } } } } return args.hasOption("nooutput") ? "" : out.toString(); } catch (StackOverflowError e) { throw new CommandExitException("Stack overflow", 2, e); } catch (FileNotFoundException e) { throw new CommandException(66, e.getMessage(), e); } catch (IOException e) { throw new CommandExitException("I/O error: " + e.getMessage(), 11); } } public static final String hh_eval = "upn expression" ; public String ac_eval_$_1_99( Args args )throws CommandException{ Stack<String> v = new Stack<>() ; for( int i = 0 ; i < args.argc() ; i++ ){ if( args.argv(i).equals("==") ){ // ------------- Object right = v.pop() ; Object left = v.pop() ; v.push(right.equals(left) ?"0" :"1") ; }else if( args.argv(i).equals("!=") ){ // ------------------- Object right = v.pop() ; Object left = v.pop() ; v.push(right.equals(left)?"1":"0") ; }else if( args.argv(i).equals("&&") ){ // ------------------- Object right = v.pop() ; Object left = v.pop() ; v.push( right.equals("0")&&left.equals("0")? "0":"1") ; }else if( args.argv(i).equals("||") ){ // ------------------- Object right = v.pop() ; Object left = v.pop() ; v.push( right.equals("0")||left.equals("0")? "0":"1") ; }else if( args.argv(i).equals("!") ){ // ------------------- Object right = v.pop() ; v.push(right.equals("0")?"1":"0") ; }else{ v.push( args.argv(i).trim() ) ; } } if( v.size() != 1 ) { throw new CommandException( 2 , "Stack position violation (" + v.size() + ')') ; } String result = v.firstElement() ; if( result.equals("0") ) { return ""; } int rc; try{ rc = Integer.parseInt(result) ; }catch(NumberFormatException nfe){ rc = 3 ; } throw new CommandEvaluationException( rc , "Eval Result : "+result ) ; } public static final String hh_define_context = "<contextName> [<delimiter>]" ; public String ac_define_context_$_1_2( Args args ){ _contextName = args.argv(0) ; _contextDelimiter = args.argc() > 1 ? args.argv(1) : "." ; _contextString = new StringBuilder() ; return "" ; } public static final String hh_define_env = "<environmentName>" ; public String ac_define_env_$_1_2( Args args ){ _envName = args.argv(0) ; _envDelimiter = args.argc() > 1 ? args.argv(1) : "." ; _envString = new StringBuilder(); return "" ; } public static final String hh_load_context = "[-b] <contextName> <fileName>" ; public String ac_load_context_$_2( Args args ) throws CommandException { String name = args.argv(0) ; File file = new File( args.argv(1) ) ; if( ! file.canRead() ) { throw new CommandException("File not found : " + args.argv(1)); } if( ( args.optc() != 0 ) && ( args.optv(0).equals("-b") ) ){ FileInputStream in = null ; try{ long fileLength = file.length() ; byte [] buffer = new byte[(int)fileLength] ; in = new FileInputStream( file ) ; in.read( buffer ) ; in.close() ; _nucleus.getDomainContext().put( name , buffer ) ; }catch( IOException ioe ){ throw new CommandException( 11 , "Problem with file : "+file+" : "+ioe ) ; }finally{ if(in != null) { try { in.close(); } catch (IOException eeee) { } } } }else{ StringBuilder sb = new StringBuilder(); BufferedReader reader = null ; String line; try{ reader = new BufferedReader( new FileReader( file ) ) ; while( ( line = reader.readLine() ) != null ) { sb.append(line).append('\n'); } }catch( IOException ioe ){ throw new CommandException( 11 , "Problem with file : "+file+" : "+ioe ) ; }finally{ if(reader != null) { try { reader.close(); } catch (IOException eeee) { } } } _nucleus.getDomainContext().put( name , sb.toString() ) ; } return "Loaded ... " ; } //////////////////////////////////////////////////////////// // // the incredible copy command // public static final String fh_copy = " copy <fromCellURL> <toCellURL>\n"+ " <fromCellURL> : <extendedCellURL>\n"+ " Protocols : env/context/cell/http/file/ftp\n"+ " <toCellURL> : <env/context CellURL>\n"+ " Protocols : env/context\n\n" + " Protocols :\n"+ " env:<environmentVariable>\n"+ " context:<contextVariable>\n"+ " context://<cellPath>/<contextVariable>\n"+ " cell://<cellPath>/<requestString>\n" ; public static final String hh_copy = "<fromCellURL> <toCellURL>" ; public String ac_copy_$_2( Args args ) throws CommandException { URI from; URI to; try { from = new URI(args.argv(0)); to = new URI(args.argv(1)); } catch (URISyntaxException e) { throw new CommandException(43, "Invalid URL: " + e); } if (from.equals(to)) { throw new CommandException(43, "Source and destination URL must not be the same"); } String source; try { try (BufferedReader in = new BufferedReader(open(from))) { String line; StringBuilder sb = new StringBuilder(); while ((line = in.readLine()) != null) { sb.append(line).append('\n'); } source = sb.toString(); } } catch (IOException e) { throw new CommandException(43, e.toString()); } String scheme = to.getScheme(); if (scheme == null) { scheme = "env"; } String destination = to.getSchemeSpecificPart(); if (destination == null) { throw new CommandException( 43 , "Destination missing"); } switch (scheme) { case "env": _environment.put(destination, source); break; case "context": _nucleus.getDomainContext().put(destination, source); break; default: throw new CommandException(43, "Unsupported scheme for destination:" + scheme); } return "" ; } //////////////////////////////////////////////////////////// // // ---------------------------------------------- // public static final String hh_exit = "[<exitCode> [<exitMessage>]]" ; public String ac_exit_$_0_2( Args args ) throws CommandExitException { String msg = "" ; int code = 0 ; if( args.argc() > 0 ){ try{ code = Integer.parseInt(args.argv(0)); }catch( Exception e ){ code = 0 ; } if( args.argc() > 1 ){ msg = args.argv(1) ; } } throw new CommandExitException( msg , code ) ; } private Reader open(URI uri) throws IOException { String scheme = uri.getScheme(); String ssp = uri.getSchemeSpecificPart(); if (scheme == null) { return new InputStreamReader(uri.toURL().openStream()); } else if (scheme.equals("context")) { String host = uri.getHost(); String path = uri.getPath(); if (host == null) { return _nucleus.getDomainContextReader(ssp); } else { if (path == null || path.length() < 2) { throw new MalformedURLException("Cell URI must be on the form: context://domainname/variable"); } Object o = getRemoteData("System@" + host, "show context " + path.substring(1), 4000); if (o instanceof Exception) { throw new IOException(o.toString()); } return new StringReader(o.toString()); } } else if (scheme.equals("env")) { Object o = _environment.get(ssp); if (o == null) { throw new IOException("Variable is not defined: " + ssp); } return new StringReader(o.toString()); } else if (scheme.equals("cell")) { String host = uri.getHost(); String path = uri.getPath(); if (host == null || path == null || path.length() < 2) { throw new MalformedURLException("Cell URI must be on the form: cell://cellname/command"); } Object o = getRemoteData(host, path.substring(1), 4000); if (o instanceof Exception) { throw new IOException(o.toString()); } return new StringReader(o.toString()); } else { return new InputStreamReader(uri.toURL().openStream()); } } private Object getRemoteData(String path, String command, long timeout) throws IOException { try { CellMessage answer = _nucleus.sendAndWait(new CellMessage(new CellPath(path), command), timeout); if (answer == null) { throw new IOException("Request timed out"); } return answer.getMessageObject(); } catch (InterruptedException e) { throw new InterruptedIOException(e.toString()); } catch (ExecutionException | NoRouteToCellException e){ throw new IOException("sendAndWait : " + e); } } private interface Tester { /** check for something */ boolean test(); /** Useful message if answer is false */ String getMessage(); } //////////////////////////////////////////////////////////// // // domain class loader routines // @Command(name = "set classloader", hint = "obsolete") @Deprecated public class SetClassloaderCommand implements Callable<String> { @Argument String[] args; @CommandLine(allowAnyOption = true) Args cmd; @Override public String call() throws IllegalArgumentException { return "obsolete"; } } @Command(name = "show classloader", hint = "obsolete") @Deprecated public class ShowClassloaderCommand implements Callable<String> { @Argument String[] args; @CommandLine(allowAnyOption = true) Args cmd; @Override public String call() { return "obsolete"; } } @Command(name = "zk ls", hint = "list zookeeper node") public class ZooKeeperList implements Callable<String> { @Argument(required = false) String path = "/"; @Override public String call() throws Exception { return String.join("\n", _nucleus.getCuratorFramework().getChildren().forPath(path)); } } @Command(name = "zk get", hint = "get zookeeper node data") public class ZooKeeperGet implements Callable<String> { @Argument String path; @Override public String call() throws Exception { return new String(_nucleus.getCuratorFramework().getData().forPath(path), StandardCharsets.UTF_8); } } /** * Test if a cell is running. */ private class CellRunningTester implements Tester { private final String _name; CellRunningTester(Args args) { _name = args.argv(0); } @Override public boolean test() { return _nucleus.getCellInfo(_name) != null; } @Override public String getMessage() { return _name + " is not running"; } } /** * Test presence of a file. */ private static class FileExistsTester implements Tester { private final File _file; FileExistsTester(Args args) { _file = new File(args.argv(0)); } @Override public boolean test() { return _file.exists(); } @Override public String getMessage() { return _file + " does not exist"; } } /** * Test presence of a file and that the file is * not special */ private static class FileIsNormalTester implements Tester { private final File _file; private boolean _exists; FileIsNormalTester(Args args) { _file = new File(args.argv(0)); } @Override public boolean test() { _exists = _file.exists(); return _file.isFile(); } @Override public String getMessage() { return _file + (_exists ? " is not a normal file" : " does not exist"); } } /** * Test presence of a file and that the file is * not special */ private static class FileIsDirectoryTester implements Tester { private final File _file; private boolean _exists; FileIsDirectoryTester(Args args) { _file = new File(args.argv(0)); } @Override public boolean test() { _exists = _file.exists(); return _file.isDirectory(); } @Override public String getMessage() { return _file + (_exists ? " is not a directory file" : " does not exist"); } } }