RYA-104 Implemented the Rya Shell integration with the Mongo DB interactors.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rya/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-rya/commit/9e8f4a65 Tree: http://git-wip-us.apache.org/repos/asf/incubator-rya/tree/9e8f4a65 Diff: http://git-wip-us.apache.org/repos/asf/incubator-rya/diff/9e8f4a65 Branch: refs/heads/master Commit: 9e8f4a654f47edc7d06fa5ba7bc7011f4716549c Parents: b642261 Author: kchilton2 <[email protected]> Authored: Sun Dec 17 15:23:41 2017 -0500 Committer: kchilton2 <[email protected]> Committed: Fri Jan 5 16:48:40 2018 -0500 ---------------------------------------------------------------------- .../client/mongo/MongoConnectionDetails.java | 4 +- .../org/apache/rya/shell/RyaAdminCommands.java | 112 ++++++++++++--- .../apache/rya/shell/RyaConnectionCommands.java | 84 +++++++++-- .../org/apache/rya/shell/RyaPromptProvider.java | 7 +- .../org/apache/rya/shell/SharedShellState.java | 138 ++++++++++++++++--- .../apache/rya/shell/RyaAdminCommandsTest.java | 50 +++++-- .../apache/rya/shell/SharedShellStateTest.java | 9 +- 7 files changed, 337 insertions(+), 67 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e8f4a65/extras/indexing/src/main/java/org/apache/rya/api/client/mongo/MongoConnectionDetails.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/org/apache/rya/api/client/mongo/MongoConnectionDetails.java b/extras/indexing/src/main/java/org/apache/rya/api/client/mongo/MongoConnectionDetails.java index 81106f9..d792289 100644 --- a/extras/indexing/src/main/java/org/apache/rya/api/client/mongo/MongoConnectionDetails.java +++ b/extras/indexing/src/main/java/org/apache/rya/api/client/mongo/MongoConnectionDetails.java @@ -46,7 +46,7 @@ public class MongoConnectionDetails { * @param username - The username that was used to establish the connection. (not null) * @param password - The password that was used to establish the connection. (not null) * @param hostname - The hostname of the Mongo DB that was connected to. (not null) - * @param port - The port of the Mongo DB that was connected to. (not null) + * @param port - The port of the Mongo DB that was connected to. */ public MongoConnectionDetails( final String username, @@ -97,7 +97,7 @@ public class MongoConnectionDetails { return build(ryaInstanceName, null); } - public MongoDBRdfConfiguration build(final String ryaInstanceName, MongoClient mongoClient) { + public MongoDBRdfConfiguration build(final String ryaInstanceName, final MongoClient mongoClient) { // Note, we don't use the MongoDBRdfConfigurationBuilder here because it explicitly sets // authorizations and visibilities to an empty string if they are not set on the builder. // If they are null in the MongoRdfConfiguration object, it may do the right thing. http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e8f4a65/extras/shell/src/main/java/org/apache/rya/shell/RyaAdminCommands.java ---------------------------------------------------------------------- diff --git a/extras/shell/src/main/java/org/apache/rya/shell/RyaAdminCommands.java b/extras/shell/src/main/java/org/apache/rya/shell/RyaAdminCommands.java index 8b86d43..cfe13dd 100644 --- a/extras/shell/src/main/java/org/apache/rya/shell/RyaAdminCommands.java +++ b/extras/shell/src/main/java/org/apache/rya/shell/RyaAdminCommands.java @@ -36,6 +36,7 @@ import org.apache.rya.api.client.RyaClientException; import org.apache.rya.api.instance.RyaDetails; import org.apache.rya.shell.SharedShellState.ConnectionState; import org.apache.rya.shell.SharedShellState.ShellState; +import org.apache.rya.shell.SharedShellState.StorageType; import org.apache.rya.shell.util.InstallPrompt; import org.apache.rya.shell.util.InstanceNamesFormatter; import org.apache.rya.shell.util.RyaDetailsFormatter; @@ -63,7 +64,8 @@ public class RyaAdminCommands implements CommandMarker { public static final String LIST_INCREMENTAL_QUERIES = "list-incremental-queries"; public static final String PRINT_INSTANCE_DETAILS_CMD = "print-instance-details"; public static final String INSTALL_CMD = "install"; - public static final String INSTALL_PARAMETERS_CMD = "install-with-parameters"; + public static final String INSTALL_ACCUMULO_PARAMETERS_CMD = "install-with-accumulo-parameters"; + public static final String INSTALL_MONGO_PARAMETERS_CMD = "install-with-mongo-parameters"; public static final String LIST_INSTANCES_CMD = "list-instances"; public static final String UNINSTALL_CMD = "uninstall"; public static final String ADD_USER_CMD = "add-user"; @@ -99,8 +101,7 @@ public class RyaAdminCommands implements CommandMarker { */ @CliAvailabilityIndicator({ LIST_INSTANCES_CMD, - INSTALL_CMD, - INSTALL_PARAMETERS_CMD}) + INSTALL_CMD}) public boolean areStorageCommandsAvailable() { switch(state.getShellState().getConnectionState()) { case CONNECTED_TO_STORAGE: @@ -112,20 +113,52 @@ public class RyaAdminCommands implements CommandMarker { } /** + * Enables commands that only become available once the Shell has been connected to an Accumulo Rya Storage. + */ + @CliAvailabilityIndicator({ + INSTALL_ACCUMULO_PARAMETERS_CMD}) + public boolean areAccumuloStorageCommandsAvailable() { + return isConnectedToStorageType(StorageType.ACCUMULO); + } + + /** + * Enables commands that only become available once the Shell has been connected to an MongoDB Rya Storage. + */ + @CliAvailabilityIndicator({ + INSTALL_MONGO_PARAMETERS_CMD}) + public boolean areMongoStorageCommandsAvailable() { + return isConnectedToStorageType(StorageType.MONGO); + } + + private boolean isConnectedToStorageType(final StorageType type) { + // Enabled if we are connected to the specified storage type. + final Optional<StorageType> storageType = state.getShellState().getStorageType(); + if(storageType.isPresent()) { + return areStorageCommandsAvailable() && storageType.get() == type; + } + + // Otherwise disabled. + return false; + } + + /** * Enables commands that are always available once the Shell is connected to a Rya Instance. */ @CliAvailabilityIndicator({ PRINT_INSTANCE_DETAILS_CMD, - UNINSTALL_CMD, + UNINSTALL_CMD}) + public boolean areInstanceCommandsAvailable() { + return state.getShellState().getConnectionState() == ConnectionState.CONNECTED_TO_INSTANCE; + } + + /** + * Enables commands that are available when connected to a Rya Instance that supports user management. + */ + @CliAvailabilityIndicator({ ADD_USER_CMD, REMOVE_USER_CMD}) - public boolean areInstanceCommandsAvailable() { - switch(state.getShellState().getConnectionState()) { - case CONNECTED_TO_INSTANCE: - return true; - default: - return false; - } + public boolean areUserCommandAvailable() { + return areInstanceCommandsAvailable() && state.getShellState().getStorageType().get() == StorageType.ACCUMULO; } /** @@ -141,7 +174,8 @@ public class RyaAdminCommands implements CommandMarker { // The PCJ commands are only available if the Shell is connected to an instance of Rya // that is new enough to use the RyaDetailsRepository and is configured to maintain PCJs. final ShellState shellState = state.getShellState(); - if(shellState.getConnectionState() == ConnectionState.CONNECTED_TO_INSTANCE) { + if(shellState.getConnectionState() == ConnectionState.CONNECTED_TO_INSTANCE && + shellState.getStorageType().get() == StorageType.ACCUMULO) { final GetInstanceDetails getInstanceDetails = shellState.getConnectedCommands().get().getGetInstanceDetails(); final String ryaInstanceName = state.getShellState().getRyaInstanceName().get(); try { @@ -211,8 +245,8 @@ public class RyaAdminCommands implements CommandMarker { } } - @CliCommand(value = INSTALL_PARAMETERS_CMD, help = "Create a new instance of Rya with command line parameters.") - public String installWithParameters( + @CliCommand(value = INSTALL_ACCUMULO_PARAMETERS_CMD, help = "Create a new Accumulo instance of Rya with command line parameters.") + public String installWithAccumuloParameters( @CliOption(key = {"instanceName"}, mandatory = true, help = "The name of the Rya instance to create.") final String instanceName, @@ -225,8 +259,9 @@ public class RyaAdminCommands implements CommandMarker { @CliOption(key = {"enableFreeTextIndex"}, mandatory = false, help = "Use Free Text Indexing.", unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") final boolean enableFreeTextIndex, - @CliOption(key = {"enableGeospatialIndex"}, mandatory = false, help = "Use Geospatial Indexing.", unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") - final boolean enableGeospatialIndex, + // TODO RYA-215 +// @CliOption(key = {"enableGeospatialIndex"}, mandatory = false, help = "Use Geospatial Indexing.", unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") +// final boolean enableGeospatialIndex, @CliOption(key = {"enableTemporalIndex"}, mandatory = false, help = "Use Temporal Indexing.", unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") final boolean enableTemporalIndex, @@ -246,7 +281,8 @@ public class RyaAdminCommands implements CommandMarker { .setEnableTableHashPrefix(enableTableHashPrefix) .setEnableEntityCentricIndex(enableEntityCentricIndex) .setEnableFreeTextIndex(enableFreeTextIndex) - .setEnableGeoIndex(enableGeospatialIndex) + // TODO RYA-215 +// .setEnableGeoIndex(enableGeospatialIndex) .setEnableTemporalIndex(enableTemporalIndex) .setEnablePcjIndex(enablePcjIndex) .setFluoPcjAppName(fluoPcjAppName) @@ -268,6 +304,48 @@ public class RyaAdminCommands implements CommandMarker { } } + @CliCommand(value = INSTALL_MONGO_PARAMETERS_CMD, help = "Create a new MongoDB instance of Rya with command line parameters.") + public String installWithMongoParameters( + @CliOption(key = {"instanceName"}, mandatory = true, help = "The name of the Rya instance to create.") + final String instanceName, + + @CliOption(key = {"enableFreeTextIndex"}, mandatory = false, help = "Use Free Text Indexing.", unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") + final boolean enableFreeTextIndex, + + // TODO RYA-215 +// @CliOption(key = {"enableGeospatialIndex"}, mandatory = false, help = "Use Geospatial Indexing.", unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") +// final boolean enableGeospatialIndex, + + @CliOption(key = {"enableTemporalIndex"}, mandatory = false, help = "Use Temporal Indexing.", unspecifiedDefaultValue = "false", specifiedDefaultValue = "true") + final boolean enableTemporalIndex) { + + // Fetch the commands that are connected to the store. + final RyaClient commands = state.getShellState().getConnectedCommands().get(); + + try { + final InstallConfiguration installConfig = InstallConfiguration.builder() + .setEnableFreeTextIndex(enableFreeTextIndex) + // TODO RYA-215 +// .setEnableGeoIndex(enableGeospatialIndex) + .setEnableTemporalIndex(enableTemporalIndex) + .build(); + + // Verify the configuration is what the user actually wants to do. + if (!installPrompt.promptVerified(instanceName, installConfig)) { + return "Skipping Installation."; + } + + // Execute the command. + commands.getInstall().install(instanceName, installConfig); + return String.format("The Rya instance named '%s' has been installed.", instanceName); + + } catch(final DuplicateInstanceNameException e) { + throw new RuntimeException(String.format("A Rya instance named '%s' already exists. Try again with a different name.", instanceName), e); + } catch (final IOException | RyaClientException e) { + throw new RuntimeException("Could not install a new instance of Rya. Reason: " + e.getMessage(), e); + } + } + @CliCommand(value = PRINT_INSTANCE_DETAILS_CMD, help = "Print information about how the Rya instance is configured.") public String printInstanceDetails() { // Fetch the command that is connected to the store. http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e8f4a65/extras/shell/src/main/java/org/apache/rya/shell/RyaConnectionCommands.java ---------------------------------------------------------------------- diff --git a/extras/shell/src/main/java/org/apache/rya/shell/RyaConnectionCommands.java b/extras/shell/src/main/java/org/apache/rya/shell/RyaConnectionCommands.java index f5ba451..e518968 100644 --- a/extras/shell/src/main/java/org/apache/rya/shell/RyaConnectionCommands.java +++ b/extras/shell/src/main/java/org/apache/rya/shell/RyaConnectionCommands.java @@ -31,7 +31,12 @@ import org.apache.rya.api.client.RyaClient; import org.apache.rya.api.client.RyaClientException; import org.apache.rya.api.client.accumulo.AccumuloConnectionDetails; import org.apache.rya.api.client.accumulo.AccumuloRyaClientFactory; +import org.apache.rya.api.client.mongo.MongoConnectionDetails; +import org.apache.rya.api.client.mongo.MongoRyaClientFactory; +import org.apache.rya.mongodb.MongoConnectorFactory; +import org.apache.rya.mongodb.MongoDBRdfConfiguration; import org.apache.rya.shell.SharedShellState.ConnectionState; +import org.apache.rya.shell.SharedShellState.StorageType; import org.apache.rya.shell.util.ConnectorFactory; import org.apache.rya.shell.util.PasswordPrompt; import org.springframework.beans.factory.annotation.Autowired; @@ -42,6 +47,7 @@ import org.springframework.shell.core.annotation.CliOption; import org.springframework.stereotype.Component; import com.google.common.base.Optional; +import com.mongodb.MongoClient; /** * Spring Shell commands that manage the connection that is used by the shell. @@ -52,6 +58,7 @@ public class RyaConnectionCommands implements CommandMarker { // Command line commands. public static final String PRINT_CONNECTION_DETAILS_CMD = "print-connection-details"; public static final String CONNECT_ACCUMULO_CMD = "connect-accumulo"; + public static final String CONNECT_MONGO_CMD = "connect-mongo"; public static final String CONNECT_INSTANCE_CMD = "connect-rya"; public static final String DISCONNECT_COMMAND_NAME_CMD = "disconnect"; @@ -75,7 +82,7 @@ public class RyaConnectionCommands implements CommandMarker { return true; } - @CliAvailabilityIndicator({CONNECT_ACCUMULO_CMD}) + @CliAvailabilityIndicator({CONNECT_ACCUMULO_CMD, CONNECT_MONGO_CMD}) public boolean areConnectCommandsAvailable() { return sharedState.getShellState().getConnectionState() == ConnectionState.DISCONNECTED; } @@ -98,17 +105,31 @@ public class RyaConnectionCommands implements CommandMarker { @CliCommand(value = PRINT_CONNECTION_DETAILS_CMD, help = "Print information about the Shell's Rya storage connection.") public String printConnectionDetails() { - final Optional<AccumuloConnectionDetails> detailsHolder = sharedState.getShellState().getConnectionDetails(); - - if(detailsHolder.isPresent()) { - final AccumuloConnectionDetails details = detailsHolder.get(); - return "The shell is connected to an instance of Accumulo using the following parameters:\n" + - " Username: " + details.getUsername() + "\n" + - " Instance Name: " + details.getInstanceName() + "\n" + - " Zookeepers: " + details.getZookeepers(); - } else { + // Check to see if the shell is connected to any storages. + final Optional<StorageType> storageType = sharedState.getShellState().getStorageType(); + if(!storageType.isPresent()) { return "The shell is not connected to anything."; } + + // Create a print out based on what it is connected to. + switch(storageType.get()) { + case ACCUMULO: + final AccumuloConnectionDetails accDetails = sharedState.getShellState().getAccumuloDetails().get(); + return "The shell is connected to an instance of Accumulo using the following parameters:\n" + + " Username: " + accDetails.getUsername() + "\n" + + " Instance Name: " + accDetails.getInstanceName() + "\n" + + " Zookeepers: " + accDetails.getZookeepers(); + + case MONGO: + final MongoConnectionDetails mongoDetails = sharedState.getShellState().getMongoDetails().get(); + return "The shell is connected to an instance of MongoDB using the following parameters:\n" + + " Hostname: " + mongoDetails.getHostname() + "\n" + + " Port: " + mongoDetails.getPort() + "\n" + + " Username:" + mongoDetails.getUsername(); + + default: + throw new RuntimeException("Unrecognized StorageType: " + storageType.get()); + } } @CliCommand(value = CONNECT_ACCUMULO_CMD, help = "Connect the shell to an instance of Accumulo.") @@ -138,6 +159,49 @@ public class RyaConnectionCommands implements CommandMarker { return "Connected. You must select a Rya instance to interact with next."; } + @CliCommand(value = CONNECT_MONGO_CMD, help = "Connect the shell to an instance of MongoDB.") + public String connectToMongo( + @CliOption(key = {"username"}, mandatory = true, help = "The username that will be used to connect to MongoDB.") + final String username, + @CliOption(key= {"hostname"}, mandatory = true, help = "The hostname of the MongoDB that will be connected to.") + final String hostname, + @CliOption(key= {"port"}, mandatory = true, help = "The port of the MongoDB that will be connected to.") + final String port) { + + // Prompt the user for their password. + try { + final char[] password = passwordPrompt.getPassword(); + + // Set up a configuration file that connects to the specified Mongo DB. + final MongoDBRdfConfiguration conf = new MongoDBRdfConfiguration(); + conf.setMongoInstance(hostname); + conf.setMongoPort(port); + conf.setMongoUser(username); + conf.setMongoPassword(new String(password)); + + // Create the singleton instance of Mongo that will be used through out the application. + final MongoClient client = MongoConnectorFactory.getMongoClient(conf); + + // Make sure the client is closed at shutdown. + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + MongoConnectorFactory.closeMongoClient(); + } + }); + + // Initialize the connected to Mongo shared state. + final MongoConnectionDetails connectionDetails = new MongoConnectionDetails(username, password, hostname, Integer.parseInt(port)); + final RyaClient ryaClient = MongoRyaClientFactory.build(connectionDetails, client); + sharedState.connectedToMongo(connectionDetails, ryaClient); + + } catch (final IOException e) { + throw new RuntimeException("Could not connection to MongoDB. Reason: " + e.getMessage(), e); + } + + return "Connected. You must select a Rya instance to interact with next."; + } + @CliCommand(value = CONNECT_INSTANCE_CMD, help = "Connect to a specific Rya instance") public void connectToInstance( @CliOption(key = {"instance"}, mandatory = true, help = "The name of the Rya instance the shell will interact with.") http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e8f4a65/extras/shell/src/main/java/org/apache/rya/shell/RyaPromptProvider.java ---------------------------------------------------------------------- diff --git a/extras/shell/src/main/java/org/apache/rya/shell/RyaPromptProvider.java b/extras/shell/src/main/java/org/apache/rya/shell/RyaPromptProvider.java index ed5f261..a7fd802 100644 --- a/extras/shell/src/main/java/org/apache/rya/shell/RyaPromptProvider.java +++ b/extras/shell/src/main/java/org/apache/rya/shell/RyaPromptProvider.java @@ -20,14 +20,13 @@ package org.apache.rya.shell; import static java.util.Objects.requireNonNull; +import org.apache.rya.shell.SharedShellState.ShellState; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.shell.plugin.support.DefaultPromptProvider; import org.springframework.stereotype.Component; -import org.apache.rya.shell.SharedShellState.ShellState; - /** * Customizes the Rya Shell's prompt. */ @@ -50,10 +49,10 @@ public class RyaPromptProvider extends DefaultPromptProvider { case DISCONNECTED: return "rya> "; case CONNECTED_TO_STORAGE: - return String.format("rya/%s> ", state.getConnectionDetails().get().getInstanceName()); + return String.format("rya/%s> ", state.getAccumuloDetails().get().getInstanceName()); case CONNECTED_TO_INSTANCE: return String.format("rya/%s:%s> ", - state.getConnectionDetails().get().getInstanceName(), + state.getAccumuloDetails().get().getInstanceName(), state.getRyaInstanceName().get()); default: return "rya> "; http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e8f4a65/extras/shell/src/main/java/org/apache/rya/shell/SharedShellState.java ---------------------------------------------------------------------- diff --git a/extras/shell/src/main/java/org/apache/rya/shell/SharedShellState.java b/extras/shell/src/main/java/org/apache/rya/shell/SharedShellState.java index 526b031..6c8a57c 100644 --- a/extras/shell/src/main/java/org/apache/rya/shell/SharedShellState.java +++ b/extras/shell/src/main/java/org/apache/rya/shell/SharedShellState.java @@ -23,17 +23,18 @@ import static java.util.Objects.requireNonNull; import java.util.Objects; import java.util.concurrent.locks.ReentrantLock; -import edu.umd.cs.findbugs.annotations.Nullable; +import org.apache.rya.api.client.RyaClient; +import org.apache.rya.api.client.accumulo.AccumuloConnectionDetails; +import org.apache.rya.api.client.mongo.MongoConnectionDetails; + +import com.google.common.base.Optional; + import edu.umd.cs.findbugs.annotations.DefaultAnnotation; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; import net.jcip.annotations.Immutable; import net.jcip.annotations.ThreadSafe; -import com.google.common.base.Optional; - -import org.apache.rya.api.client.RyaClient; -import org.apache.rya.api.client.accumulo.AccumuloConnectionDetails; - /** * Holds values that are shared between the various Rya command classes. */ @@ -86,7 +87,7 @@ public class SharedShellState { // Store the connection details. shellState = ShellState.builder() .setConnectionState( ConnectionState.CONNECTED_TO_STORAGE ) - .setAccumuloConnectionDetails( connectionDetails ) + .setAccumuloDetails( connectionDetails ) .setConnectedCommands( connectedCommands ) .build(); } finally { @@ -95,6 +96,40 @@ public class SharedShellState { } /** + * This method indicates a shift into the {@link ConnectionState#CONNECTED_TO_STORAGE} state. + * <p/> + * Store the values used by a Mongo Rya Storage connection. This may only be called when + * the shell is disconnected. + * + * @param connectionDetails - Metadata about the Mongo connection. (not null) + * @param connectedCommands - Rya Commands that will execute against the Mongo database. (not null) + * @throws IllegalStateException Thrown if the shell is already connected to a Rya storage. + */ + public void connectedToMongo( + final MongoConnectionDetails connectionDetails, + final RyaClient connectedCommands) throws IllegalStateException { + requireNonNull(connectionDetails); + requireNonNull(connectedCommands); + + lock.lock(); + try { + // Ensure the Rya Shell is disconnected. + if(shellState.getConnectionState() != ConnectionState.DISCONNECTED) { + throw new IllegalStateException("You must clear the old connection state before you may set a new connection state."); + } + + // Store the connection details. + shellState = ShellState.builder() + .setConnectionState( ConnectionState.CONNECTED_TO_STORAGE ) + .setMongoDetails( connectionDetails ) + .setConnectedCommands( connectedCommands ) + .build(); + } finally { + lock.unlock(); + } + } + + /** * This method indicates a shift into the {@link ConnectionState#CONNECTED_TO_INSTANCE} state. * <p/> * Store the name of the Rya instance all commands will be executed against. @@ -160,6 +195,21 @@ public class SharedShellState { } /** + * Enumerates the various types of Rya Storages the shell may connect to. + */ + public static enum StorageType { + /** + * The Rya instances are stored in Accumulo. + */ + ACCUMULO, + + /** + * The Rya instances are stored in MongoDB. + */ + MONGO; + } + + /** * Values that define the state of a Rya Shell. */ @Immutable @@ -169,7 +219,9 @@ public class SharedShellState { private final ConnectionState connectionState; // Connection specific values. - private final Optional<AccumuloConnectionDetails> connectionDetails; + private final Optional<StorageType> storageType; + private final Optional<AccumuloConnectionDetails> accumuloDetails; + private final Optional<MongoConnectionDetails> mongoDetails; private final Optional<RyaClient> connectedCommands; // Instance specific values. @@ -177,11 +229,15 @@ public class SharedShellState { private ShellState( final ConnectionState connectionState, - final Optional<AccumuloConnectionDetails> connectionDetails, + final Optional<StorageType> storageType, + final Optional<AccumuloConnectionDetails> accumuloDetails, + final Optional<MongoConnectionDetails> mongoDetails, final Optional<RyaClient> connectedCommands, final Optional<String> instanceName) { this.connectionState = requireNonNull(connectionState); - this.connectionDetails = requireNonNull(connectionDetails); + this.storageType = requireNonNull(storageType); + this.accumuloDetails = requireNonNull(accumuloDetails); + this.mongoDetails = requireNonNull(mongoDetails); this.connectedCommands = requireNonNull(connectedCommands); this.instanceName = requireNonNull(instanceName); } @@ -194,11 +250,28 @@ public class SharedShellState { } /** + * @return The type of storage the shell is connected to if it is connected to a storage. + */ + public Optional<StorageType> getStorageType() { + return storageType; + } + + /** * @return Metadata about the Accumulo connection. The value will not be present - * if the Rya Shell is not connected to a storage. + * if the Rya Shell is not connected to a storage or is connected to another type + * of storage. */ - public Optional<AccumuloConnectionDetails> getConnectionDetails() { - return connectionDetails; + public Optional<AccumuloConnectionDetails> getAccumuloDetails() { + return accumuloDetails; + } + + /** + * @return Metadata about the Mongo connection. The value will not be present + * if the Rya Shell is not connected to a storage or is connected to another type + * of storage. + */ + public Optional<MongoConnectionDetails> getMongoDetails() { + return mongoDetails; } /** @@ -220,7 +293,7 @@ public class SharedShellState { @Override public int hashCode() { - return Objects.hash(connectionState, connectionDetails, connectedCommands, instanceName); + return Objects.hash(connectionState, accumuloDetails, connectedCommands, instanceName); } @Override @@ -231,7 +304,7 @@ public class SharedShellState { if(obj instanceof ShellState) { final ShellState state = (ShellState)obj; return Objects.equals(connectionState, state.connectionState) && - Objects.equals(connectionDetails, state.connectionDetails) && + Objects.equals(accumuloDetails, state.accumuloDetails) && Objects.equals(connectedCommands, state.connectedCommands) && Objects.equals(instanceName, state.instanceName); } @@ -264,7 +337,9 @@ public class SharedShellState { private ConnectionState connectionState; // Connection specific values. - private AccumuloConnectionDetails connectionDetails; + private StorageType storageType; + private AccumuloConnectionDetails accumuloDetails; + private MongoConnectionDetails mongoDetails; private RyaClient connectedCommands; // Instance specific values. @@ -283,7 +358,7 @@ public class SharedShellState { */ public Builder(final ShellState shellState) { this.connectionState = shellState.getConnectionState(); - this.connectionDetails = shellState.getConnectionDetails().orNull(); + this.accumuloDetails = shellState.getAccumuloDetails().orNull(); this.connectedCommands = shellState.getConnectedCommands().orNull(); this.instanceName = shellState.getRyaInstanceName().orNull(); } @@ -298,11 +373,30 @@ public class SharedShellState { } /** - * @param connectionDetails - Metadata about the Accumulo connection. + * @param accumuloDetails - Metadata about the Accumulo connection. + * @return This {@link Builder} so that method invocations may be chained. + */ + public Builder setAccumuloDetails(@Nullable final AccumuloConnectionDetails accumuloDetails) { + // If we are setting the details, clear any old ones. + if(accumuloDetails != null) { + this.storageType = StorageType.ACCUMULO; + this.mongoDetails = null; + } + this.accumuloDetails = accumuloDetails; + return this; + } + + /** + * @param mongoDetails - Metadata about the Mongo connection. * @return This {@link Builder} so that method invocations may be chained. */ - public Builder setAccumuloConnectionDetails(@Nullable final AccumuloConnectionDetails connectionDetails) { - this.connectionDetails = connectionDetails; + public Builder setMongoDetails(@Nullable final MongoConnectionDetails mongoDetails) { + // If we are setting the details, clear any old ones. + if(mongoDetails != null) { + this.storageType = StorageType.MONGO; + this.accumuloDetails = null; + } + this.mongoDetails = mongoDetails; return this; } @@ -330,7 +424,9 @@ public class SharedShellState { public ShellState build() { return new ShellState( connectionState, - Optional.fromNullable(connectionDetails), + Optional.fromNullable(storageType), + Optional.fromNullable(accumuloDetails), + Optional.fromNullable(mongoDetails), Optional.fromNullable(connectedCommands), Optional.fromNullable(instanceName)); } http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e8f4a65/extras/shell/src/test/java/org/apache/rya/shell/RyaAdminCommandsTest.java ---------------------------------------------------------------------- diff --git a/extras/shell/src/test/java/org/apache/rya/shell/RyaAdminCommandsTest.java b/extras/shell/src/test/java/org/apache/rya/shell/RyaAdminCommandsTest.java index 6e21f8d..d8d5b8f 100644 --- a/extras/shell/src/test/java/org/apache/rya/shell/RyaAdminCommandsTest.java +++ b/extras/shell/src/test/java/org/apache/rya/shell/RyaAdminCommandsTest.java @@ -48,6 +48,7 @@ import org.apache.rya.api.client.RyaClient; import org.apache.rya.api.client.RyaClientException; import org.apache.rya.api.client.Uninstall; import org.apache.rya.api.client.accumulo.AccumuloConnectionDetails; +import org.apache.rya.api.client.mongo.MongoConnectionDetails; import org.apache.rya.api.instance.RyaDetails; import org.apache.rya.api.instance.RyaDetails.EntityCentricIndexDetails; import org.apache.rya.api.instance.RyaDetails.FreeTextIndexDetails; @@ -354,7 +355,7 @@ public class RyaAdminCommandsTest { } @Test - public void installWithParameters() throws DuplicateInstanceNameException, RyaClientException, IOException { + public void installWithAccumuloParameters() throws DuplicateInstanceNameException, RyaClientException, IOException { // Mock the object that performs the install operation. final Install mockInstall = mock(Install.class); @@ -368,7 +369,6 @@ public class RyaAdminCommandsTest { final boolean enableTableHashPrefix = false; final boolean enableEntityCentricIndex = true; final boolean enableFreeTextIndex = false; - final boolean enableGeospatialIndex = true; final boolean enableTemporalIndex = false; final boolean enablePcjIndex = true; final String fluoPcjAppName = instanceName + "pcj_updater"; @@ -378,7 +378,6 @@ public class RyaAdminCommandsTest { .setEnableTableHashPrefix(enableTableHashPrefix) .setEnableEntityCentricIndex(enableEntityCentricIndex) .setEnableFreeTextIndex(enableFreeTextIndex) - .setEnableGeoIndex(enableGeospatialIndex) .setEnableTemporalIndex(enableTemporalIndex) .setEnablePcjIndex(enablePcjIndex) .setFluoPcjAppName(fluoPcjAppName) @@ -390,7 +389,7 @@ public class RyaAdminCommandsTest { when(mockInstallPrompt.promptVerified(eq(instanceName), eq(installConfig))).thenReturn(true); final RyaAdminCommands commands = new RyaAdminCommands(state, mockInstallPrompt, mock(SparqlPrompt.class), mock(UninstallPrompt.class)); - final String message = commands.installWithParameters(instanceName, enableTableHashPrefix, enableEntityCentricIndex, enableFreeTextIndex, enableGeospatialIndex, enableTemporalIndex, enablePcjIndex, fluoPcjAppName); + final String message = commands.installWithAccumuloParameters(instanceName, enableTableHashPrefix, enableEntityCentricIndex, enableFreeTextIndex, enableTemporalIndex, enablePcjIndex, fluoPcjAppName); // Verify the values that were provided to the command were passed through to the Install. verify(mockInstall).install(eq(instanceName), eq(installConfig)); @@ -401,7 +400,7 @@ public class RyaAdminCommandsTest { } @Test - public void installWithParameters_userAbort() throws DuplicateInstanceNameException, RyaClientException, IOException { + public void installWithAccumuloParameters_userAbort() throws DuplicateInstanceNameException, RyaClientException, IOException { // Mock the object that performs the install operation. final Install mockInstall = mock(Install.class); @@ -415,7 +414,6 @@ public class RyaAdminCommandsTest { final boolean enableTableHashPrefix = false; final boolean enableEntityCentricIndex = true; final boolean enableFreeTextIndex = false; - final boolean enableGeospatialIndex = true; final boolean enableTemporalIndex = false; final boolean enablePcjIndex = true; final String fluoPcjAppName = instanceName + "pcj_updater"; @@ -425,7 +423,6 @@ public class RyaAdminCommandsTest { .setEnableTableHashPrefix(enableTableHashPrefix) .setEnableEntityCentricIndex(enableEntityCentricIndex) .setEnableFreeTextIndex(enableFreeTextIndex) - .setEnableGeoIndex(enableGeospatialIndex) .setEnableTemporalIndex(enableTemporalIndex) .setEnablePcjIndex(enablePcjIndex) .setFluoPcjAppName(fluoPcjAppName) @@ -437,7 +434,7 @@ public class RyaAdminCommandsTest { when(mockInstallPrompt.promptVerified(eq(instanceName), eq(installConfig))).thenReturn(false); final RyaAdminCommands commands = new RyaAdminCommands(state, mockInstallPrompt, mock(SparqlPrompt.class), mock(UninstallPrompt.class)); - final String message = commands.installWithParameters(instanceName, enableTableHashPrefix, enableEntityCentricIndex, enableFreeTextIndex, enableGeospatialIndex, enableTemporalIndex, enablePcjIndex, fluoPcjAppName); + final String message = commands.installWithAccumuloParameters(instanceName, enableTableHashPrefix, enableEntityCentricIndex, enableFreeTextIndex, enableTemporalIndex, enablePcjIndex, fluoPcjAppName); // Verify a message is returned that indicates the success of the operation. final String expected = "Skipping Installation."; @@ -445,6 +442,43 @@ public class RyaAdminCommandsTest { } @Test + public void installWithMongoParameters() throws DuplicateInstanceNameException, RyaClientException, IOException { + // Mock the object that performs the install operation. + final Install mockInstall = mock(Install.class); + + final RyaClient mockCommands = mock(RyaClient.class); + when(mockCommands.getInstall()).thenReturn( mockInstall ); + + final SharedShellState state = new SharedShellState(); + state.connectedToMongo(mock(MongoConnectionDetails.class), mockCommands); + + final String instanceName = "unitTests"; + final boolean enableFreeTextIndex = false; + final boolean enableTemporalIndex = false; + + // Execute the command. + final InstallConfiguration installConfig = InstallConfiguration.builder() + .setEnableFreeTextIndex(enableFreeTextIndex) + .setEnableTemporalIndex(enableTemporalIndex) + .build(); + + final InstallPrompt mockInstallPrompt = mock(InstallPrompt.class); + when(mockInstallPrompt.promptInstanceName()).thenReturn( instanceName ); + when(mockInstallPrompt.promptInstallConfiguration(instanceName)).thenReturn( installConfig ); + when(mockInstallPrompt.promptVerified(eq(instanceName), eq(installConfig))).thenReturn(true); + + final RyaAdminCommands commands = new RyaAdminCommands(state, mockInstallPrompt, mock(SparqlPrompt.class), mock(UninstallPrompt.class)); + final String message = commands.installWithMongoParameters(instanceName, enableFreeTextIndex, enableTemporalIndex); + + // Verify the values that were provided to the command were passed through to the Install. + verify(mockInstall).install(eq(instanceName), eq(installConfig)); + + // Verify a message is returned that indicates the success of the operation. + final String expected = "The Rya instance named 'unitTests' has been installed."; + assertEquals(expected, message); + } + + @Test public void listInstances() throws RyaClientException, IOException { // Mock the object that performs the list operation. final ListInstances mockListInstances = mock(ListInstances.class); http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e8f4a65/extras/shell/src/test/java/org/apache/rya/shell/SharedShellStateTest.java ---------------------------------------------------------------------- diff --git a/extras/shell/src/test/java/org/apache/rya/shell/SharedShellStateTest.java b/extras/shell/src/test/java/org/apache/rya/shell/SharedShellStateTest.java index e79d186..b5f136c 100644 --- a/extras/shell/src/test/java/org/apache/rya/shell/SharedShellStateTest.java +++ b/extras/shell/src/test/java/org/apache/rya/shell/SharedShellStateTest.java @@ -21,12 +21,11 @@ package org.apache.rya.shell; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; -import org.junit.Test; - import org.apache.rya.api.client.RyaClient; import org.apache.rya.api.client.accumulo.AccumuloConnectionDetails; import org.apache.rya.shell.SharedShellState.ConnectionState; import org.apache.rya.shell.SharedShellState.ShellState; +import org.junit.Test; /** * Tests the methods of {@link SharedShellState}. @@ -57,7 +56,7 @@ public class SharedShellStateTest { // Verify the state. final ShellState expected = ShellState.builder() .setConnectionState(ConnectionState.CONNECTED_TO_STORAGE) - .setAccumuloConnectionDetails(connectionDetails) + .setAccumuloDetails(connectionDetails) .setConnectedCommands(connectedCommands) .build(); @@ -92,7 +91,7 @@ public class SharedShellStateTest { // Verify the state. final ShellState expected = ShellState.builder() .setConnectionState(ConnectionState.CONNECTED_TO_INSTANCE) - .setAccumuloConnectionDetails(connectionDetails) + .setAccumuloDetails(connectionDetails) .setConnectedCommands(connectedCommands) .setRyaInstanceName("instance") .build(); @@ -118,7 +117,7 @@ public class SharedShellStateTest { // Verify the state. final ShellState expected = ShellState.builder() .setConnectionState(ConnectionState.CONNECTED_TO_INSTANCE) - .setAccumuloConnectionDetails(connectionDetails) + .setAccumuloDetails(connectionDetails) .setConnectedCommands(connectedCommands) .setRyaInstanceName("secondInstance") .build();
