package dmg.util.command; import com.google.common.base.MoreObjects; import com.google.common.base.Throwables; import java.io.Serializable; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import dmg.util.CommandException; import dmg.util.CommandPanicException; import dmg.util.CommandSyntaxException; import dmg.util.CommandThrowableException; import org.dcache.util.Args; import org.dcache.util.cli.CommandExecutor; /** * Implements the legacy cell shell commands which use reflection * on method and field names. */ class AcCommandExecutor implements CommandExecutor { private final Object _listener; private Method _method; private int _minArgs; private int _maxArgs; private Field _fullHelp; private Field _helpHint; private Field _acls; private boolean _isDeprecated; public AcCommandExecutor(Object listener) { _listener = listener; } @Override public boolean isDeprecated() { return _isDeprecated; } public void setMethod(Method m, int mn, int mx) { _method = m; _minArgs = mn; _maxArgs = mx; _isDeprecated = m.getDeclaredAnnotation(Deprecated.class) != null; } public void setFullHelpField(Field f) { _fullHelp = f; } public void setHelpHintField(Field f) { _helpHint = f; } public void setAclField(Field f) { _acls = f; } @Override public boolean hasACLs() { return _acls != null; } @Override public String[] getACLs() { try { if (_acls != null) { Object value = _acls.get(_listener); if (value instanceof String[]) { return (String[]) value; } else if (value instanceof String) { return new String[] { value.toString() }; } } } catch (IllegalAccessException ee) { // REVISIT: might be dangerous, as in case of a coding error the ACLs // get silently ignored. } return new String[0]; } @Override public String getFullHelp(HelpFormat format) { try { if (_fullHelp != null) { Object help = _fullHelp.get(_listener); if (help != null) { return help.toString(); } } } catch (IllegalAccessException e) { throw new RuntimeException(e); } return null; } @Override public String getHelpHint(HelpFormat format) { try { if (_helpHint != null) { Object hint = _helpHint.get(_listener); if (hint != null) { return hint.toString(); } } else { StringBuilder sb = new StringBuilder(); for (int i = 0; i < _minArgs; i++) { sb.append(" <arg-").append(i).append('>'); } if (_maxArgs != _minArgs) { sb.append(" [ "); for (int i = _minArgs; i < _maxArgs; i++) { sb.append(" <arg-").append(i).append('>'); } sb.append(" ] "); } return sb.toString(); } } catch (IllegalAccessException e) { throw new RuntimeException(e); } return null; } @Override public Serializable execute(Args arguments) throws CommandException { int params = arguments.argc(); if ((params < _minArgs) || (params > _maxArgs)) { throw new CommandSyntaxException("Invalid number of arguments"); } // // everything seems to be fine right now. // so we invoke the selected function. // try { return (Serializable) _method.invoke(_listener, arguments); } catch (InvocationTargetException e) { Throwable te = e.getTargetException(); Throwables.throwIfInstanceOf(te, CommandException.class); Throwables.throwIfInstanceOf(te, Error.class); if (te instanceof RuntimeException && !(te instanceof IllegalArgumentException) && !(te instanceof IllegalStateException)) { /* We treat uncaught RuntimeExceptions other than * IllegalArgumentException, IllegalStateException, * and those declared to be thrown by the method as * bugs and rethrow them. */ boolean declared = false; for (Class<?> clazz: _method.getExceptionTypes()) { if (clazz.isAssignableFrom(te.getClass())) { declared = true; } } if (!declared) { throw new CommandPanicException("Command failed: " + te, te); } } throw new CommandThrowableException(te + " from " + _method.getName(), te); } catch (IllegalAccessException e) { throw new CommandPanicException("Exception while invoking " + _method.getName() + ": " + e, e); } } @Override public AnnotatedElement getImplementation() { return _method; } @Override public String toString() { return MoreObjects.toStringHelper(this) .addValue(_method) .addValue(_fullHelp) .addValue(_helpHint) .addValue(_acls) .omitNullValues() .toString(); } }