ACCUMULO-3514 Use auto-service for start Use @AutoService annotations and Java's ServiceLoader mechanism to discover classes which are executable by Accumulo's "start" jar with a keyword.
This replaces manual intervention whenever we add a new option to the bin/accumulo script and also auto-populates the usage for that script. Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/8005e82c Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/8005e82c Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/8005e82c Branch: refs/heads/master Commit: 8005e82c7ea8599ddbfe4b04e21f1f4dd44b5644 Parents: a2d272c Author: Christopher Tubbs <ctubb...@apache.org> Authored: Fri Jan 23 20:32:33 2015 -0500 Committer: Christopher Tubbs <ctubb...@apache.org> Committed: Wed Feb 4 15:14:07 2015 -0500 ---------------------------------------------------------------------- core/pom.xml | 5 + .../accumulo/core/file/rfile/PrintInfo.java | 16 +- .../apache/accumulo/core/util/Classpath.java | 35 +++ .../apache/accumulo/core/util/CreateToken.java | 19 +- .../org/apache/accumulo/core/util/Help.java | 35 +++ .../java/org/apache/accumulo/core/util/Jar.java | 59 ++++ .../org/apache/accumulo/core/util/Version.java | 22 +- minicluster/pom.xml | 5 + .../minicluster/MiniAccumuloRunner.java | 2 +- .../minicluster/impl/MiniClusterExecutable.java | 37 +++ pom.xml | 5 + proxy/pom.xml | 5 + .../java/org/apache/accumulo/proxy/Proxy.java | 17 +- server/base/pom.xml | 5 + .../apache/accumulo/server/init/Initialize.java | 36 ++- .../org/apache/accumulo/server/util/Admin.java | 31 +- .../org/apache/accumulo/server/util/Info.java | 20 +- .../accumulo/server/util/LoginProperties.java | 21 +- .../accumulo/server/util/ZooKeeperMain.java | 15 +- server/gc/pom.xml | 5 + .../org/apache/accumulo/gc/GCExecutable.java | 36 +++ server/master/pom.xml | 5 + .../accumulo/master/MasterExecutable.java | 36 +++ server/monitor/pom.xml | 5 + .../accumulo/monitor/MonitorExecutable.java | 36 +++ server/tracer/pom.xml | 5 + .../accumulo/tracer/TracerExecutable.java | 36 +++ server/tserver/pom.xml | 5 + .../accumulo/tserver/TServerExecutable.java | 36 +++ shell/pom.xml | 5 + .../java/org/apache/accumulo/shell/Shell.java | 28 +- .../java/org/apache/accumulo/start/Main.java | 300 ++++++++++--------- .../accumulo/start/spi/KeywordExecutable.java | 54 ++++ .../org/apache/accumulo/start/MainTest.java | 12 +- 34 files changed, 802 insertions(+), 192 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/core/pom.xml ---------------------------------------------------------------------- diff --git a/core/pom.xml b/core/pom.xml index 5fc7a6e..67b486e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -31,6 +31,11 @@ <artifactId>jcommander</artifactId> </dependency> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/core/src/main/java/org/apache/accumulo/core/file/rfile/PrintInfo.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/file/rfile/PrintInfo.java b/core/src/main/java/org/apache/accumulo/core/file/rfile/PrintInfo.java index f29efcc..9ff1dd2 100644 --- a/core/src/main/java/org/apache/accumulo/core/file/rfile/PrintInfo.java +++ b/core/src/main/java/org/apache/accumulo/core/file/rfile/PrintInfo.java @@ -30,14 +30,18 @@ import org.apache.accumulo.core.data.Value; import org.apache.accumulo.core.file.blockfile.impl.CachableBlockFile; import org.apache.accumulo.core.file.rfile.RFile.Reader; import org.apache.accumulo.core.volume.VolumeConfiguration; +import org.apache.accumulo.start.spi.KeywordExecutable; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.log4j.Logger; import com.beust.jcommander.Parameter; +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class PrintInfo implements KeywordExecutable { -public class PrintInfo { private static final Logger log = Logger.getLogger(PrintInfo.class); static class Opts extends Help { @@ -50,6 +54,16 @@ public class PrintInfo { } public static void main(String[] args) throws Exception { + new PrintInfo().execute(args); + } + + @Override + public String keyword() { + return "rfile-info"; + } + + @Override + public void execute(final String[] args) throws Exception { Configuration conf = new Configuration(); AccumuloConfiguration aconf = SiteConfiguration.getInstance(DefaultConfiguration.getInstance()); http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/core/src/main/java/org/apache/accumulo/core/util/Classpath.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/util/Classpath.java b/core/src/main/java/org/apache/accumulo/core/util/Classpath.java new file mode 100644 index 0000000..242ca52 --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/util/Classpath.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.core.util; + +import org.apache.accumulo.start.Main; +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class Classpath implements KeywordExecutable { + @Override + public String keyword() { + return "classpath"; + } + + @Override + public void execute(final String[] args) throws Exception { + Main.getVFSClassLoader().getMethod("printClassPath", new Class[0]).invoke(Main.getVFSClassLoader(), new Object[0]); + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/core/src/main/java/org/apache/accumulo/core/util/CreateToken.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/util/CreateToken.java b/core/src/main/java/org/apache/accumulo/core/util/CreateToken.java index 79b241c..adb7c3d 100644 --- a/core/src/main/java/org/apache/accumulo/core/util/CreateToken.java +++ b/core/src/main/java/org/apache/accumulo/core/util/CreateToken.java @@ -33,14 +33,17 @@ import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.Authe import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.Properties; import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.TokenProperty; import org.apache.accumulo.core.client.security.tokens.PasswordToken; +import org.apache.accumulo.start.spi.KeywordExecutable; import com.beust.jcommander.Parameter; +import com.google.auto.service.AutoService; -public class CreateToken { +@AutoService(KeywordExecutable.class) +public class CreateToken implements KeywordExecutable { - private static ConsoleReader reader = null; + private ConsoleReader reader = null; - private static ConsoleReader getConsoleReader() throws IOException { + private ConsoleReader getConsoleReader() throws IOException { if (reader == null) reader = new ConsoleReader(); return reader; @@ -65,6 +68,16 @@ public class CreateToken { } public static void main(String[] args) { + new CreateToken().execute(args); + } + + @Override + public String keyword() { + return "create-token"; + } + + @Override + public void execute(String[] args) { Opts opts = new Opts(); opts.parseArgs(CreateToken.class.getName(), args); http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/core/src/main/java/org/apache/accumulo/core/util/Help.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/util/Help.java b/core/src/main/java/org/apache/accumulo/core/util/Help.java new file mode 100644 index 0000000..fda72fe --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/util/Help.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.core.util; + +import org.apache.accumulo.start.Main; +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class Help implements KeywordExecutable { + @Override + public String keyword() { + return "help"; + } + + @Override + public void execute(final String[] args) throws Exception { + Main.printUsage(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/core/src/main/java/org/apache/accumulo/core/util/Jar.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/util/Jar.java b/core/src/main/java/org/apache/accumulo/core/util/Jar.java new file mode 100644 index 0000000..2fc6d17 --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/util/Jar.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.core.util; + +import java.io.IOException; +import java.util.jar.JarFile; + +import org.apache.accumulo.start.Main; +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class Jar implements KeywordExecutable { + @Override + public String keyword() { + return "jar"; + } + + @Override + public void execute(final String[] args) throws Exception { + // need at least one argument for the jar file, two arguments if the jar file manifest doesn't specify a main class + if (args.length == 0) { + Main.printUsage(); + System.exit(1); + } + String jarFileName = args[0]; + String candidateMainClass = args.length > 1 ? args[1] : null; + Class<?> mainClass = null; + try { + JarFile f = new JarFile(jarFileName); + mainClass = Main.loadClassFromJar(args, f, Main.getClassLoader()); + } catch (IOException ioe) { + System.out.println("File " + jarFileName + " could not be found or read."); + System.exit(1); + } catch (ClassNotFoundException cnfe) { + System.out.println("Classname " + (candidateMainClass != null ? candidateMainClass : "in JAR manifest") + + " not found. Please make sure you use the wholly qualified package name."); + System.exit(1); + } + // strip the jar file name and, if specified, the main class name from the args; then execute + String[] newArgs = Main.stripArgs(args, mainClass.getName().equals(candidateMainClass) ? 2 : 1); + Main.execMainClass(mainClass, newArgs); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/core/src/main/java/org/apache/accumulo/core/util/Version.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/util/Version.java b/core/src/main/java/org/apache/accumulo/core/util/Version.java index ee645ff..069e5b1 100644 --- a/core/src/main/java/org/apache/accumulo/core/util/Version.java +++ b/core/src/main/java/org/apache/accumulo/core/util/Version.java @@ -19,7 +19,27 @@ package org.apache.accumulo.core.util; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class Version { +import org.apache.accumulo.start.Main; +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class Version implements KeywordExecutable { + + public Version() {} + + @Override + public String keyword() { + return "version"; + } + + @Override + public void execute(final String[] args) throws Exception { + Class<?> runTMP = Main.getClassLoader().loadClass("org.apache.accumulo.core.Constants"); + System.out.println(runTMP.getField("VERSION").get(null)); + } + String package_ = null; int major = 0; int minor = 0; http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/minicluster/pom.xml ---------------------------------------------------------------------- diff --git a/minicluster/pom.xml b/minicluster/pom.xml index ee6cdc8..adec106 100644 --- a/minicluster/pom.xml +++ b/minicluster/pom.xml @@ -31,6 +31,11 @@ <artifactId>jcommander</artifactId> </dependency> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/minicluster/src/main/java/org/apache/accumulo/minicluster/MiniAccumuloRunner.java ---------------------------------------------------------------------- diff --git a/minicluster/src/main/java/org/apache/accumulo/minicluster/MiniAccumuloRunner.java b/minicluster/src/main/java/org/apache/accumulo/minicluster/MiniAccumuloRunner.java index c45abc0..b727f14 100644 --- a/minicluster/src/main/java/org/apache/accumulo/minicluster/MiniAccumuloRunner.java +++ b/minicluster/src/main/java/org/apache/accumulo/minicluster/MiniAccumuloRunner.java @@ -136,7 +136,7 @@ public class MiniAccumuloRunner { * @param args * An optional -p argument can be specified with the path to a valid properties file. */ - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws IOException, InterruptedException { Opts opts = new Opts(); opts.parseArgs(MiniAccumuloRunner.class.getName(), args); http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/minicluster/src/main/java/org/apache/accumulo/minicluster/impl/MiniClusterExecutable.java ---------------------------------------------------------------------- diff --git a/minicluster/src/main/java/org/apache/accumulo/minicluster/impl/MiniClusterExecutable.java b/minicluster/src/main/java/org/apache/accumulo/minicluster/impl/MiniClusterExecutable.java new file mode 100644 index 0000000..ecd5988 --- /dev/null +++ b/minicluster/src/main/java/org/apache/accumulo/minicluster/impl/MiniClusterExecutable.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.minicluster.impl; + +import org.apache.accumulo.minicluster.MiniAccumuloRunner; +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class MiniClusterExecutable implements KeywordExecutable { + + @Override + public String keyword() { + return "minicluster"; + } + + @Override + public void execute(final String[] args) throws Exception { + MiniAccumuloRunner.main(args); + } + +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index dda1cfe..78aeb0c 100644 --- a/pom.xml +++ b/pom.xml @@ -150,6 +150,11 @@ <version>1.32</version> </dependency> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <version>1.0-rc2</version> + </dependency> + <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.2.2</version> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/proxy/pom.xml ---------------------------------------------------------------------- diff --git a/proxy/pom.xml b/proxy/pom.xml index 9312d7b..7da1326 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -31,6 +31,11 @@ <artifactId>jcommander</artifactId> </dependency> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java ---------------------------------------------------------------------- diff --git a/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java b/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java index 0a4d12e..f9039be 100644 --- a/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java +++ b/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java @@ -39,6 +39,7 @@ import org.apache.accumulo.server.rpc.TServerUtils; import org.apache.accumulo.server.rpc.ThriftServerType; import org.apache.accumulo.server.rpc.TimedProcessor; import org.apache.accumulo.server.rpc.UGIAssumingProcessor; +import org.apache.accumulo.start.spi.KeywordExecutable; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.security.UserGroupInformation; import org.apache.log4j.Logger; @@ -48,10 +49,12 @@ import org.apache.thrift.protocol.TProtocolFactory; import com.beust.jcommander.IStringConverter; import com.beust.jcommander.Parameter; +import com.google.auto.service.AutoService; import com.google.common.io.Files; import com.google.common.net.HostAndPort; -public class Proxy { +@AutoService(KeywordExecutable.class) +public class Proxy implements KeywordExecutable { private static final Logger log = Logger.getLogger(Proxy.class); @@ -99,7 +102,13 @@ public class Proxy { Properties prop; } - public static void main(String[] args) throws Exception { + @Override + public String keyword() { + return "proxy"; + } + + @Override + public void execute(final String[] args) throws Exception { Opts opts = new Opts(); opts.parseArgs(Proxy.class.getName(), args); @@ -161,6 +170,10 @@ public class Proxy { } } + public static void main(String[] args) throws Exception { + new Proxy().execute(args); + } + public static ServerAddress createProxyServer(HostAndPort address, TProtocolFactory protocolFactory, Properties properties) throws Exception { final int numThreads = Integer.parseInt(properties.getProperty(THRIFT_THREAD_POOL_SIZE_KEY, THRIFT_THREAD_POOL_SIZE_DEFAULT)); final long maxFrameSize = AccumuloConfiguration.getMemoryInBytes(properties.getProperty(THRIFT_MAX_FRAME_SIZE_KEY, THRIFT_MAX_FRAME_SIZE_DEFAULT)); http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/base/pom.xml ---------------------------------------------------------------------- diff --git a/server/base/pom.xml b/server/base/pom.xml index c21a168..e01da1c 100644 --- a/server/base/pom.xml +++ b/server/base/pom.xml @@ -32,6 +32,11 @@ <artifactId>jcommander</artifactId> </dependency> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java index 0a1f411..495e0e0 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java +++ b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java @@ -20,6 +20,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.ServerColumnFamily.DIRECTORY_COLUMN; import static org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.ServerColumnFamily.TIME_COLUMN; import static org.apache.accumulo.core.metadata.schema.MetadataSchema.TabletsSection.TabletColumnFamily.PREV_ROW_COLUMN; + import java.io.FileNotFoundException; import java.io.IOException; import java.util.Arrays; @@ -34,6 +35,7 @@ import java.util.TreeMap; import java.util.UUID; import jline.console.ConsoleReader; + import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.cli.Help; import org.apache.accumulo.core.client.AccumuloSecurityException; @@ -94,6 +96,7 @@ import org.apache.accumulo.server.tablets.TabletTime; import org.apache.accumulo.server.util.ReplicationTableUtil; import org.apache.accumulo.server.util.TablePropUtil; import org.apache.accumulo.server.zookeeper.ZooReaderWriter; +import org.apache.accumulo.start.spi.KeywordExecutable; import org.apache.commons.lang.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; @@ -106,6 +109,7 @@ import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooDefs.Ids; import com.beust.jcommander.Parameter; +import com.google.auto.service.AutoService; import com.google.common.base.Joiner; import com.google.common.base.Optional; @@ -113,7 +117,8 @@ import com.google.common.base.Optional; * This class is used to setup the directory structure and the root tablet to get an instance started * */ -public class Initialize { +@AutoService(KeywordExecutable.class) +public class Initialize implements KeywordExecutable { private static final Logger log = Logger.getLogger(Initialize.class); private static final String DEFAULT_ROOT_USER = "root"; private static final String TABLE_TABLETS_TABLET_DIR = "/table_info"; @@ -267,7 +272,7 @@ public class Initialize { log.fatal("The current value of " + Property.INSTANCE_VOLUMES + " is |" + instanceVolumes + "|"); } - public static boolean doInit(Opts opts, Configuration conf, VolumeManager fs) throws IOException { + public boolean doInit(Opts opts, Configuration conf, VolumeManager fs) throws IOException { if (!checkInit(conf, fs, SiteConfiguration.getInstance())) { return false; } @@ -301,7 +306,7 @@ public class Initialize { return initialize(opts, instanceNamePath, fs, rootUser); } - private static boolean initialize(Opts opts, String instanceNamePath, VolumeManager fs, String rootUser) { + private boolean initialize(Opts opts, String instanceNamePath, VolumeManager fs, String rootUser) { UUID uuid = UUID.randomUUID(); // the actual disk locations of the root table and tablets @@ -399,7 +404,7 @@ public class Initialize { } } - private static void initFileSystem(Opts opts, VolumeManager fs, UUID uuid, String rootTabletDir) throws IOException { + private void initFileSystem(Opts opts, VolumeManager fs, UUID uuid, String rootTabletDir) throws IOException { initDirs(fs, uuid, VolumeConfiguration.getVolumeUris(SiteConfiguration.getInstance()), false); // initialize initial system tables config in zookeeper @@ -539,7 +544,7 @@ public class Initialize { zoo.putPersistentData(zkInstanceRoot + ReplicationConstants.ZOO_TSERVERS, EMPTY_BYTE_ARRAY, NodeExistsPolicy.FAIL); } - private static String getInstanceNamePath(Opts opts) throws IOException, KeeperException, InterruptedException { + private String getInstanceNamePath(Opts opts) throws IOException, KeeperException, InterruptedException { // setup the instance name String instanceName, instanceNamePath = null; boolean exists = true; @@ -571,7 +576,7 @@ public class Initialize { return instanceNamePath; } - private static String getRootUserName(Opts opts) throws IOException { + private String getRootUserName(Opts opts) throws IOException { AccumuloConfiguration conf = SiteConfiguration.getInstance(); final String keytab = conf.get(Property.GENERAL_KERBEROS_KEYTAB); if (keytab.equals(Property.GENERAL_KERBEROS_KEYTAB.getDefaultValue()) || !conf.getBoolean(Property.INSTANCE_RPC_SASL_ENABLED)) { @@ -597,7 +602,7 @@ public class Initialize { } while (true); } - private static byte[] getRootPassword(Opts opts, String rootUser) throws IOException { + private byte[] getRootPassword(Opts opts, String rootUser) throws IOException { if (opts.cliPassword != null) { return opts.cliPassword.getBytes(UTF_8); } @@ -693,11 +698,10 @@ public class Initialize { UUID uuid = UUID.fromString(ZooUtil.getInstanceIDFromHdfs(iidPath, SiteConfiguration.getInstance())); for (Pair<Path,Path> replacementVolume : ServerConstants.getVolumeReplacements()) { if (aBasePath.equals(replacementVolume.getSecond())) - log.error(aBasePath + " is set to be replaced in " + Property.INSTANCE_VOLUMES_REPLACEMENTS + " and should not appear in " + - Property.INSTANCE_VOLUMES + ". It is highly recommended that this property be removed as data could still be written to this volume."); + log.error(aBasePath + " is set to be replaced in " + Property.INSTANCE_VOLUMES_REPLACEMENTS + " and should not appear in " + Property.INSTANCE_VOLUMES + + ". It is highly recommended that this property be removed as data could still be written to this volume."); } - if (ServerConstants.DATA_VERSION != Accumulo.getAccumuloPersistentVersion(versionPath.getFileSystem(CachedConfiguration.getInstance()), versionPath)) { throw new IOException("Accumulo " + Constants.VERSION + " cannot initialize data version " + Accumulo.getAccumuloPersistentVersion(fs)); } @@ -722,7 +726,13 @@ public class Initialize { byte[] rootpass = null; } - public static void main(String[] args) { + @Override + public String keyword() { + return "init"; + } + + @Override + public void execute(final String[] args) { Opts opts = new Opts(); opts.parseArgs(Initialize.class.getName(), args); @@ -756,4 +766,8 @@ public class Initialize { throw new RuntimeException(e); } } + + public static void main(String[] args) { + new Initialize().execute(args); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java b/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java index 77d5ea1..adf3364 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java +++ b/server/base/src/main/java/org/apache/accumulo/server/util/Admin.java @@ -58,16 +58,19 @@ import org.apache.accumulo.server.AccumuloServerContext; import org.apache.accumulo.server.cli.ClientOpts; import org.apache.accumulo.server.conf.ServerConfigurationFactory; import org.apache.accumulo.server.security.SecurityUtil; +import org.apache.accumulo.start.spi.KeywordExecutable; import org.apache.hadoop.conf.Configuration; import org.apache.log4j.Logger; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; +import com.google.auto.service.AutoService; import com.google.common.collect.Lists; import com.google.common.net.HostAndPort; -public class Admin { +@AutoService(KeywordExecutable.class) +public class Admin implements KeywordExecutable { private static final Logger log = Logger.getLogger(Admin.class); static class AdminOpts extends ClientOpts { @@ -139,6 +142,16 @@ public class Admin { } public static void main(String[] args) { + new Admin().execute(args); + } + + @Override + public String keyword() { + return "admin"; + } + + @Override + public void execute(final String[] args) { boolean everything; AdminOpts opts = new AdminOpts(); @@ -368,11 +381,11 @@ public class Admin { private static final MessageFormat tablePermFormat = new MessageFormat("grant Table.{0} -t {1} -u {2}\n"); private static final MessageFormat userAuthsFormat = new MessageFormat("setauths -u {0} -s {1}\n"); - private static DefaultConfiguration defaultConfig; - private static Map<String,String> siteConfig, systemConfig; - private static List<String> localUsers; + private DefaultConfiguration defaultConfig; + private Map<String,String> siteConfig, systemConfig; + private List<String> localUsers; - public static void printConfig(ClientContext context, DumpConfigCommand opts) throws Exception { + public void printConfig(ClientContext context, DumpConfigCommand opts) throws Exception { File outputDirectory = null; if (opts.directory != null) { @@ -431,7 +444,7 @@ public class Admin { } } - private static String getDefaultConfigValue(String key) { + private String getDefaultConfigValue(String key) { if (null == key) return null; @@ -445,7 +458,7 @@ public class Admin { return defaultValue; } - private static void printNameSpaceConfiguration(Connector connector, String namespace, File outputDirectory) throws IOException, AccumuloException, + private void printNameSpaceConfiguration(Connector connector, String namespace, File outputDirectory) throws IOException, AccumuloException, AccumuloSecurityException, NamespaceNotFoundException { File namespaceScript = new File(outputDirectory, namespace + NS_FILE_SUFFIX); FileWriter nsWriter = new FileWriter(namespaceScript); @@ -495,7 +508,7 @@ public class Admin { userWriter.close(); } - private static void printSystemConfiguration(Connector connector, File outputDirectory) throws IOException, AccumuloException, AccumuloSecurityException { + private void printSystemConfiguration(Connector connector, File outputDirectory) throws IOException, AccumuloException, AccumuloSecurityException { Configuration conf = new Configuration(false); TreeMap<String,String> site = new TreeMap<String,String>(siteConfig); for (Entry<String,String> prop : site.entrySet()) { @@ -520,7 +533,7 @@ public class Admin { } } - private static void printTableConfiguration(Connector connector, String tableName, File outputDirectory) throws AccumuloException, TableNotFoundException, + private void printTableConfiguration(Connector connector, String tableName, File outputDirectory) throws AccumuloException, TableNotFoundException, IOException, AccumuloSecurityException { File tableBackup = new File(outputDirectory, tableName + ".cfg"); FileWriter writer = new FileWriter(tableBackup); http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/base/src/main/java/org/apache/accumulo/server/util/Info.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/Info.java b/server/base/src/main/java/org/apache/accumulo/server/util/Info.java index 29fa135..d5440a6 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/util/Info.java +++ b/server/base/src/main/java/org/apache/accumulo/server/util/Info.java @@ -19,12 +19,28 @@ package org.apache.accumulo.server.util; import org.apache.accumulo.core.client.Instance; import org.apache.accumulo.core.util.MonitorUtil; import org.apache.accumulo.server.client.HdfsZooInstance; +import org.apache.accumulo.start.spi.KeywordExecutable; +import org.apache.zookeeper.KeeperException; -public class Info { - public static void main(String[] args) throws Exception { +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class Info implements KeywordExecutable { + + @Override + public String keyword() { + return "info"; + } + + @Override + public void execute(final String[] args) throws KeeperException, InterruptedException { Instance instance = HdfsZooInstance.getInstance(); System.out.println("monitor: " + MonitorUtil.getLocation(instance)); System.out.println("masters: " + instance.getMasterLocations()); System.out.println("zookeepers: " + instance.getZooKeepers()); } + + public static void main(String[] args) throws Exception { + new Info().execute(args); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/base/src/main/java/org/apache/accumulo/server/util/LoginProperties.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/LoginProperties.java b/server/base/src/main/java/org/apache/accumulo/server/util/LoginProperties.java index be5a7c8..8ffe586 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/util/LoginProperties.java +++ b/server/base/src/main/java/org/apache/accumulo/server/util/LoginProperties.java @@ -28,13 +28,20 @@ import org.apache.accumulo.server.client.HdfsZooInstance; import org.apache.accumulo.server.conf.ServerConfigurationFactory; import org.apache.accumulo.server.security.handler.Authenticator; import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; +import org.apache.accumulo.start.spi.KeywordExecutable; -/** - * - */ -public class LoginProperties { +import com.google.auto.service.AutoService; - public static void main(String[] args) throws Exception { +@AutoService(KeywordExecutable.class) +public class LoginProperties implements KeywordExecutable { + + @Override + public String keyword() { + return "login-info"; + } + + @Override + public void execute(String[] args) throws Exception { AccumuloConfiguration config = new ServerConfigurationFactory(HdfsZooInstance.getInstance()).getConfiguration(); Authenticator authenticator = AccumuloVFSClassLoader.getClassLoader().loadClass(config.get(Property.INSTANCE_SECURITY_AUTHENTICATOR)) .asSubclass(Authenticator.class).newInstance(); @@ -56,4 +63,8 @@ public class LoginProperties { System.out.println(); } } + + public static void main(String[] args) throws Exception { + new LoginProperties().execute(args); + } } http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/base/src/main/java/org/apache/accumulo/server/util/ZooKeeperMain.java ---------------------------------------------------------------------- diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/ZooKeeperMain.java b/server/base/src/main/java/org/apache/accumulo/server/util/ZooKeeperMain.java index 0edcf71..c8ef6d5 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/util/ZooKeeperMain.java +++ b/server/base/src/main/java/org/apache/accumulo/server/util/ZooKeeperMain.java @@ -21,12 +21,15 @@ import org.apache.accumulo.core.client.Instance; import org.apache.accumulo.server.ServerConstants; import org.apache.accumulo.server.client.HdfsZooInstance; import org.apache.accumulo.server.fs.VolumeManagerImpl; +import org.apache.accumulo.start.spi.KeywordExecutable; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import com.beust.jcommander.Parameter; +import com.google.auto.service.AutoService; -public class ZooKeeperMain { +@AutoService(KeywordExecutable.class) +public class ZooKeeperMain implements KeywordExecutable { static class Opts extends Help { @@ -38,6 +41,16 @@ public class ZooKeeperMain { } public static void main(String[] args) throws Exception { + new ZooKeeperMain().execute(args); + } + + @Override + public String keyword() { + return "zookeeper"; + } + + @Override + public void execute(final String[] args) throws Exception { Opts opts = new Opts(); opts.parseArgs(ZooKeeperMain.class.getName(), args); FileSystem fs = VolumeManagerImpl.get().getDefaultVolume().getFileSystem(); http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/gc/pom.xml ---------------------------------------------------------------------- diff --git a/server/gc/pom.xml b/server/gc/pom.xml index 9602b95..694ffe9 100644 --- a/server/gc/pom.xml +++ b/server/gc/pom.xml @@ -32,6 +32,11 @@ <artifactId>jcommander</artifactId> </dependency> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/gc/src/main/java/org/apache/accumulo/gc/GCExecutable.java ---------------------------------------------------------------------- diff --git a/server/gc/src/main/java/org/apache/accumulo/gc/GCExecutable.java b/server/gc/src/main/java/org/apache/accumulo/gc/GCExecutable.java new file mode 100644 index 0000000..0c74444 --- /dev/null +++ b/server/gc/src/main/java/org/apache/accumulo/gc/GCExecutable.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.gc; + +import java.io.IOException; + +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class GCExecutable implements KeywordExecutable { + @Override + public String keyword() { + return "gc"; + } + + @Override + public void execute(final String[] args) throws IOException { + SimpleGarbageCollector.main(args); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/master/pom.xml ---------------------------------------------------------------------- diff --git a/server/master/pom.xml b/server/master/pom.xml index 7e9ab1d..dbeb429 100644 --- a/server/master/pom.xml +++ b/server/master/pom.xml @@ -32,6 +32,11 @@ <artifactId>jcommander</artifactId> </dependency> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/master/src/main/java/org/apache/accumulo/master/MasterExecutable.java ---------------------------------------------------------------------- diff --git a/server/master/src/main/java/org/apache/accumulo/master/MasterExecutable.java b/server/master/src/main/java/org/apache/accumulo/master/MasterExecutable.java new file mode 100644 index 0000000..aabfa6d --- /dev/null +++ b/server/master/src/main/java/org/apache/accumulo/master/MasterExecutable.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.master; + +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class MasterExecutable implements KeywordExecutable { + + @Override + public String keyword() { + return "master"; + } + + @Override + public void execute(final String[] args) throws Exception { + Master.main(args); + } + +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/monitor/pom.xml ---------------------------------------------------------------------- diff --git a/server/monitor/pom.xml b/server/monitor/pom.xml index ba61aeb..51262c1 100644 --- a/server/monitor/pom.xml +++ b/server/monitor/pom.xml @@ -28,6 +28,11 @@ <description>A web server for monitoring Apache Accumulo.</description> <dependencies> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/monitor/src/main/java/org/apache/accumulo/monitor/MonitorExecutable.java ---------------------------------------------------------------------- diff --git a/server/monitor/src/main/java/org/apache/accumulo/monitor/MonitorExecutable.java b/server/monitor/src/main/java/org/apache/accumulo/monitor/MonitorExecutable.java new file mode 100644 index 0000000..9da7519 --- /dev/null +++ b/server/monitor/src/main/java/org/apache/accumulo/monitor/MonitorExecutable.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.monitor; + +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class MonitorExecutable implements KeywordExecutable { + + @Override + public String keyword() { + return "monitor"; + } + + @Override + public void execute(final String[] args) throws Exception { + Monitor.main(args); + } + +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/tracer/pom.xml ---------------------------------------------------------------------- diff --git a/server/tracer/pom.xml b/server/tracer/pom.xml index ac9f45f..b895d67 100644 --- a/server/tracer/pom.xml +++ b/server/tracer/pom.xml @@ -28,6 +28,11 @@ <description>The tracer server for Apache Accumulo to listen for, and store, distributed tracing messages.</description> <dependencies> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/tracer/src/main/java/org/apache/accumulo/tracer/TracerExecutable.java ---------------------------------------------------------------------- diff --git a/server/tracer/src/main/java/org/apache/accumulo/tracer/TracerExecutable.java b/server/tracer/src/main/java/org/apache/accumulo/tracer/TracerExecutable.java new file mode 100644 index 0000000..3995924 --- /dev/null +++ b/server/tracer/src/main/java/org/apache/accumulo/tracer/TracerExecutable.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.tracer; + +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class TracerExecutable implements KeywordExecutable { + + @Override + public String keyword() { + return "tracer"; + } + + @Override + public void execute(final String[] args) throws Exception { + TraceServer.main(args); + } + +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/tserver/pom.xml ---------------------------------------------------------------------- diff --git a/server/tserver/pom.xml b/server/tserver/pom.xml index cd0f8ef..96eb046 100644 --- a/server/tserver/pom.xml +++ b/server/tserver/pom.xml @@ -32,6 +32,11 @@ <artifactId>jcommander</artifactId> </dependency> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/server/tserver/src/main/java/org/apache/accumulo/tserver/TServerExecutable.java ---------------------------------------------------------------------- diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/TServerExecutable.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/TServerExecutable.java new file mode 100644 index 0000000..4c197ca --- /dev/null +++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/TServerExecutable.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.tserver; + +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class TServerExecutable implements KeywordExecutable { + + @Override + public String keyword() { + return "tserver"; + } + + @Override + public void execute(final String[] args) throws Exception { + TabletServer.main(args); + } + +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/shell/pom.xml ---------------------------------------------------------------------- diff --git a/shell/pom.xml b/shell/pom.xml index db3530f..6ac997f 100644 --- a/shell/pom.xml +++ b/shell/pom.xml @@ -31,6 +31,11 @@ <artifactId>jcommander</artifactId> </dependency> <dependency> + <groupId>com.google.auto.service</groupId> + <artifactId>auto-service</artifactId> + <optional>true</optional> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/shell/src/main/java/org/apache/accumulo/shell/Shell.java ---------------------------------------------------------------------- diff --git a/shell/src/main/java/org/apache/accumulo/shell/Shell.java b/shell/src/main/java/org/apache/accumulo/shell/Shell.java index a64ff45..b63f291 100644 --- a/shell/src/main/java/org/apache/accumulo/shell/Shell.java +++ b/shell/src/main/java/org/apache/accumulo/shell/Shell.java @@ -165,6 +165,7 @@ import org.apache.accumulo.shell.commands.UsersCommand; import org.apache.accumulo.shell.commands.WhoAmICommand; import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; import org.apache.accumulo.start.classloader.vfs.ContextManager; +import org.apache.accumulo.start.spi.KeywordExecutable; import org.apache.commons.cli.BasicParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; @@ -179,11 +180,13 @@ import org.apache.log4j.Logger; import com.beust.jcommander.JCommander; import com.beust.jcommander.ParameterException; +import com.google.auto.service.AutoService; /** * A convenient console interface to perform basic accumulo functions Includes auto-complete, help, and quoted strings with escape sequences */ -public class Shell extends ShellOptions { +@AutoService(KeywordExecutable.class) +public class Shell extends ShellOptions implements KeywordExecutable { public static final Logger log = Logger.getLogger(Shell.class); private static final Logger audit = Logger.getLogger(Shell.class.getName() + ".audit"); @@ -535,20 +538,29 @@ public class Shell extends ShellOptions { return classloader; } - public static void main(String args[]) throws IOException { - Shell shell = new Shell(); - try{ - if (!shell.config(args)) { - System.exit(shell.getExitCode()); + @Override + public String keyword() { + return "shell"; + } + + @Override + public void execute(final String[] args) throws IOException { + try { + if (!config(args)) { + System.exit(getExitCode()); } - System.exit(shell.start()); + System.exit(start()); } finally { - shell.shutdown(); + shutdown(); DistributedTrace.disable(); } } + public static void main(String args[]) throws IOException { + new Shell().execute(args); + } + public int start() throws IOException { String input; if (isVerbose()) http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/start/src/main/java/org/apache/accumulo/start/Main.java ---------------------------------------------------------------------- diff --git a/start/src/main/java/org/apache/accumulo/start/Main.java b/start/src/main/java/org/apache/accumulo/start/Main.java index c820883..fa79196 100644 --- a/start/src/main/java/org/apache/accumulo/start/Main.java +++ b/start/src/main/java/org/apache/accumulo/start/Main.java @@ -20,167 +20,139 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Collections; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.TreeMap; +import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarFile; import org.apache.accumulo.start.classloader.AccumuloClassLoader; +import org.apache.accumulo.start.spi.KeywordExecutable; import org.apache.log4j.Logger; public class Main { private static final Logger log = Logger.getLogger(Main.class); + private static ClassLoader classLoader; + private static Class<?> vfsClassLoader; + private static Map<String,KeywordExecutable> servicesMap; - public static void main(String[] args) { - Runnable r = null; - + public static void main(final String[] args) { try { if (args.length == 0) { printUsage(); System.exit(1); } - Thread.currentThread().setContextClassLoader(AccumuloClassLoader.getClassLoader()); - - Class<?> vfsClassLoader = AccumuloClassLoader.getClassLoader().loadClass("org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader"); - - ClassLoader cl = (ClassLoader) vfsClassLoader.getMethod("getClassLoader", new Class[] {}).invoke(null, new Object[] {}); - - Class<?> runTMP = null; - - Thread.currentThread().setContextClassLoader(cl); - - switch (args[0]) { - case "help": - printUsage(); - System.exit(0); - break; - case "master": - runTMP = cl.loadClass("org.apache.accumulo.master.Master"); - break; - case "tserver": - runTMP = cl.loadClass("org.apache.accumulo.tserver.TabletServer"); - break; - case "shell": - runTMP = cl.loadClass("org.apache.accumulo.shell.Shell"); - break; - case "init": - runTMP = cl.loadClass("org.apache.accumulo.server.init.Initialize"); - break; - case "admin": - runTMP = cl.loadClass("org.apache.accumulo.server.util.Admin"); - break; - case "gc": - runTMP = cl.loadClass("org.apache.accumulo.gc.SimpleGarbageCollector"); - break; - case "monitor": - runTMP = cl.loadClass("org.apache.accumulo.monitor.Monitor"); - break; - case "tracer": - runTMP = cl.loadClass("org.apache.accumulo.tracer.TraceServer"); - break; - case "proxy": - runTMP = cl.loadClass("org.apache.accumulo.proxy.Proxy"); - break; - case "minicluster": - runTMP = cl.loadClass("org.apache.accumulo.minicluster.MiniAccumuloRunner"); - break; - case "classpath": - vfsClassLoader.getMethod("printClassPath", new Class[] {}).invoke(vfsClassLoader, new Object[] {}); - return; - case "version": - runTMP = cl.loadClass("org.apache.accumulo.core.Constants"); - System.out.println(runTMP.getField("VERSION").get(null)); - return; - case "rfile-info": - runTMP = cl.loadClass("org.apache.accumulo.core.file.rfile.PrintInfo"); - break; - case "login-info": - runTMP = cl.loadClass("org.apache.accumulo.server.util.LoginProperties"); - break; - case "zookeeper": - runTMP = cl.loadClass("org.apache.accumulo.server.util.ZooKeeperMain"); - break; - case "create-token": - runTMP = cl.loadClass("org.apache.accumulo.core.util.CreateToken"); - break; - case "info": - runTMP = cl.loadClass("org.apache.accumulo.server.util.Info"); - break; - case "jar": - if (args.length < 2) { - printUsage(); - System.exit(1); - } - try { - JarFile f = new JarFile(args[1]); - runTMP = loadClassFromJar(args, f, cl); - } catch (IOException ioe) { - System.out.println("File " + args[1] + " could not be found or read."); - System.exit(1); - } catch (ClassNotFoundException cnfe) { - System.out.println("Classname " + (args.length > 2 ? args[2] : "in JAR manifest") - + " not found. Please make sure you use the wholly qualified package name."); - System.exit(1); - } - break; - default: - try { - runTMP = cl.loadClass(args[0]); - } catch (ClassNotFoundException cnfe) { - System.out.println("Classname " + args[0] + " not found. Please make sure you use the wholly qualified package name."); - System.exit(1); - } - break; + // determine whether a keyword was used or a class name, and execute it with the remaining args + String keywordOrClassName = args[0]; + KeywordExecutable keywordExec = getExecutables(getClassLoader()).get(keywordOrClassName); + if (keywordExec != null) { + execKeyword(keywordExec, stripArgs(args, 1)); + } else { + execMainClassName(keywordOrClassName, stripArgs(args, 1)); } - Method main = null; + + } catch (Throwable t) { + log.error("Uncaught exception", t); + System.exit(1); + } + } + + public static ClassLoader getClassLoader() { + if (classLoader == null) { try { - main = runTMP.getMethod("main", args.getClass()); - } catch (Throwable t) { - log.error("Could not run main method on '" + runTMP.getName() + "'.", t); - } - if (main == null || !Modifier.isPublic(main.getModifiers()) || !Modifier.isStatic(main.getModifiers())) { - System.out.println(args[0] + " must implement a public static void main(String args[]) method"); + ClassLoader clTmp = (ClassLoader) getVFSClassLoader().getMethod("getClassLoader", new Class[0]).invoke(null, new Object[0]); + classLoader = clTmp; + } catch (ClassNotFoundException | IOException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException + | SecurityException e) { + log.error("Problem initializing the class loader", e); System.exit(1); } - int chopArgsCount; - if (args[0].equals("jar")) { - if (args.length > 2 && runTMP.getName().equals(args[2])) { - chopArgsCount = 3; - } else { - chopArgsCount = 2; + } + return classLoader; + } + + public static Class<?> getVFSClassLoader() throws IOException, ClassNotFoundException { + if (vfsClassLoader == null) { + Thread.currentThread().setContextClassLoader(AccumuloClassLoader.getClassLoader()); + Class<?> vfsClassLoaderTmp = AccumuloClassLoader.getClassLoader().loadClass("org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader"); + vfsClassLoader = vfsClassLoaderTmp; + } + return vfsClassLoader; + } + + private static void execKeyword(final KeywordExecutable keywordExec, final String[] args) { + Runnable r = new Runnable() { + @Override + public void run() { + try { + keywordExec.execute(args); + } catch (Exception e) { + die(e); } - } else { - chopArgsCount = 1; } - String argsToPass[] = new String[args.length - chopArgsCount]; - System.arraycopy(args, chopArgsCount, argsToPass, 0, args.length - chopArgsCount); - final Object thisIsJustOneArgument = argsToPass; - final Method finalMain = main; - r = new Runnable() { - @Override - public void run() { - try { - finalMain.invoke(null, thisIsJustOneArgument); - } catch (InvocationTargetException e) { - if (e.getCause() != null) { - die(e.getCause()); - } else { - // Should never happen, but check anyway. - die(e); - } - } catch (Exception e) { - die(e); - } - } - }; + }; + startThread(r, keywordExec.keyword()); + } - Thread t = new Thread(r, args[0]); - t.setContextClassLoader(cl); - t.start(); + private static void execMainClassName(final String className, final String[] args) { + Class<?> classWithMain = null; + try { + classWithMain = getClassLoader().loadClass(className); + } catch (ClassNotFoundException cnfe) { + System.out.println("Classname " + className + " not found. Please make sure you use the wholly qualified package name."); + System.exit(1); + } + execMainClass(classWithMain, args); + } + + public static void execMainClass(final Class<?> classWithMain, final String[] args) { + Method main = null; + try { + main = classWithMain.getMethod("main", args.getClass()); } catch (Throwable t) { - log.error("Uncaught exception", t); + log.error("Could not run main method on '" + classWithMain.getName() + "'.", t); + } + if (main == null || !Modifier.isPublic(main.getModifiers()) || !Modifier.isStatic(main.getModifiers())) { + System.out.println(classWithMain.getName() + " must implement a public static void main(String args[]) method"); System.exit(1); } + final Method finalMain = main; + Runnable r = new Runnable() { + @Override + public void run() { + try { + final Object thisIsJustOneArgument = args; + finalMain.invoke(null, thisIsJustOneArgument); + } catch (InvocationTargetException e) { + if (e.getCause() != null) { + die(e.getCause()); + } else { + // Should never happen, but check anyway. + die(e); + } + } catch (Exception e) { + die(e); + } + } + }; + startThread(r, classWithMain.getName()); + } + + public static String[] stripArgs(final String[] originalArgs, int numToStrip) { + int newSize = originalArgs.length - numToStrip; + String newArgs[] = new String[newSize]; + System.arraycopy(originalArgs, numToStrip, newArgs, 0, newSize); + return newArgs; + } + + private static void startThread(final Runnable r, final String name) { + Thread t = new Thread(r, name); + t.setContextClassLoader(getClassLoader()); + t.start(); } /** @@ -189,22 +161,65 @@ public class Main { * @param t * The {@link Throwable} containing a stack trace to print. */ - private static void die(Throwable t) { + private static void die(final Throwable t) { log.error("Thread '" + Thread.currentThread().getName() + "' died.", t); System.exit(1); } - private static void printUsage() { - System.out.println("accumulo init | master | tserver | monitor | shell | admin | gc | classpath | rfile-info | login-info " - + "| tracer | minicluster | proxy | zookeeper | create-token | info | version | help | jar <jar> [<main class>] args | <accumulo class> args"); + public static void printUsage() { + TreeSet<String> keywords = new TreeSet<>(getExecutables(getClassLoader()).keySet()); + + // jar is a special case, because it has arguments + keywords.remove("jar"); + keywords.add("jar <jar> [<main class>] args"); + + String prefix = ""; + String kwString = ""; + for (String kw : keywords) { + kwString += prefix + kw; + prefix = " | "; + } + System.out.println("accumulo " + kwString + " | <accumulo class> args"); + } + + static Map<String,KeywordExecutable> getExecutables(final ClassLoader cl) { + if (servicesMap == null) { + servicesMap = checkDuplicates(ServiceLoader.load(KeywordExecutable.class, cl)); + } + return servicesMap; + } + + static Map<String,KeywordExecutable> checkDuplicates(final Iterable<? extends KeywordExecutable> services) { + TreeSet<String> blacklist = new TreeSet<>(); + TreeMap<String,KeywordExecutable> results = new TreeMap<>(); + for (KeywordExecutable service : services) { + String keyword = service.keyword(); + if (blacklist.contains(keyword)) { + // subsequent times a duplicate is found, just warn and exclude it + warnDuplicate(service); + } else if (results.containsKey(keyword)) { + // the first time a duplicate is found, blacklist it and warn + blacklist.add(keyword); + warnDuplicate(results.remove(keyword)); + warnDuplicate(service); + } else { + // first observance of this keyword, so just add it to the list + results.put(service.keyword(), service); + } + } + return Collections.unmodifiableSortedMap(results); + } + + private static void warnDuplicate(final KeywordExecutable service) { + log.warn("Ambiguous duplicate binding for keyword '" + service.keyword() + "' found: " + service.getClass().getName()); } // feature: will work even if main class isn't in the JAR - static Class<?> loadClassFromJar(String[] args, JarFile f, ClassLoader cl) throws IOException, ClassNotFoundException { + public static Class<?> loadClassFromJar(final String[] args, final JarFile f, final ClassLoader cl) throws ClassNotFoundException, IOException { ClassNotFoundException explicitNotFound = null; - if (args.length >= 3) { + if (args.length >= 2) { try { - return cl.loadClass(args[2]); // jar jar-file main-class + return cl.loadClass(args[1]); // jar-file main-class } catch (ClassNotFoundException cnfe) { // assume this is the first argument, look for main class in JAR manifest explicitNotFound = cnfe; @@ -219,4 +234,5 @@ public class Main { } return cl.loadClass(mainClass); } + } http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/start/src/main/java/org/apache/accumulo/start/spi/KeywordExecutable.java ---------------------------------------------------------------------- diff --git a/start/src/main/java/org/apache/accumulo/start/spi/KeywordExecutable.java b/start/src/main/java/org/apache/accumulo/start/spi/KeywordExecutable.java new file mode 100644 index 0000000..9c8dbeb --- /dev/null +++ b/start/src/main/java/org/apache/accumulo/start/spi/KeywordExecutable.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.accumulo.start.spi; + +import java.util.ServiceLoader; + +/** + * An interface used with the Java {@link ServiceLoader} to auto-discover classes executable with a convenient keyword on the command-line. + * + * <p> + * All implementing classes who have an entry in META-INF/services/{@link org.apache.accumulo.start.spi.KeywordExecutable} on the classpath will be constructed + * by the {@link ServiceLoader}, so they should be lightweight and quickly constructible with a mandatory no-argument constructor. Because of this, implementing + * classes could simply be factories which execute a different class, if that class is expensive to construct or cannot have a no-argument constructor. + * + * <p> + * One way to easily create META-INF/services files is to use the <a href="https://github.com/google/auto/tree/master/service">AutoService</a> annotation. + * + * <p> + * If the implementing class also wishes to have a redundant main method, it may be useful to simply implement main as:<br> + * {@code new MyImplementingClass().execute(args);} + * + */ +public interface KeywordExecutable { + + /** + * Provides access to the service's keyword. + * + * @return the keyword which identifies this service + */ + String keyword(); + + /** + * Execute the item with the given arguments. + * + * @param args + * command-line arguments to pass to the executed class + */ + void execute(final String[] args) throws Exception; + +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/8005e82c/start/src/test/java/org/apache/accumulo/start/MainTest.java ---------------------------------------------------------------------- diff --git a/start/src/test/java/org/apache/accumulo/start/MainTest.java b/start/src/test/java/org/apache/accumulo/start/MainTest.java index 1ea22fb..0e6102d 100644 --- a/start/src/test/java/org/apache/accumulo/start/MainTest.java +++ b/start/src/test/java/org/apache/accumulo/start/MainTest.java @@ -44,7 +44,7 @@ public class MainTest { @Test public void testLoadClassFromJar_ExplicitMainClass() throws Exception { - String[] args = {"jar", "the.jar", "main.class", "arg1", "arg2"}; + String[] args = {"the.jar", "main.class", "arg1", "arg2"}; EasyMock.<Class<?>> expect(cl.loadClass("main.class")).andReturn(MAIN_CLASS); replay(cl); assertEquals(MAIN_CLASS, Main.loadClassFromJar(args, f, cl)); @@ -52,7 +52,7 @@ public class MainTest { @Test public void testLoadClassFromJar_ManifestMainClass() throws Exception { - String[] args = {"jar", "the.jar", "arg1", "arg2"}; + String[] args = {"the.jar", "arg1", "arg2"}; expect(cl.loadClass("arg1")).andThrow(new ClassNotFoundException()); EasyMock.<Class<?>> expect(cl.loadClass(MAIN_CLASS_NAME)).andReturn(MAIN_CLASS); replay(cl); @@ -63,7 +63,7 @@ public class MainTest { @Test(expected = ClassNotFoundException.class) public void testLoadClassFromJar_NoMainClass() throws Exception { - String[] args = {"jar", "the.jar", "arg1", "arg2"}; + String[] args = {"the.jar", "arg1", "arg2"}; expect(cl.loadClass("arg1")).andThrow(new ClassNotFoundException()); replay(cl); mockManifestMainClass(f, null); @@ -73,7 +73,7 @@ public class MainTest { @Test(expected = ClassNotFoundException.class) public void testLoadClassFromJar_NoMainClassNoArgs() throws Exception { - String[] args = {"jar", "the.jar"}; + String[] args = {"the.jar"}; mockManifestMainClass(f, null); replay(f); Main.loadClassFromJar(args, f, cl); @@ -81,7 +81,7 @@ public class MainTest { @Test(expected = ClassNotFoundException.class) public void testLoadClassFromJar_ExplicitMainClass_Fail() throws Exception { - String[] args = {"jar", "the.jar", "main.class", "arg1", "arg2"}; + String[] args = {"the.jar", "main.class", "arg1", "arg2"}; expect(cl.loadClass("main.class")).andThrow(new ClassNotFoundException()); replay(cl); mockManifestMainClass(f, null); @@ -91,7 +91,7 @@ public class MainTest { @Test(expected = ClassNotFoundException.class) public void testLoadClassFromJar_ManifestMainClass_Fail() throws Exception { - String[] args = {"jar", "the.jar", "arg1", "arg2"}; + String[] args = {"the.jar", "arg1", "arg2"}; expect(cl.loadClass("arg1")).andThrow(new ClassNotFoundException()); expect(cl.loadClass(MAIN_CLASS_NAME)).andThrow(new ClassNotFoundException()); replay(cl);