http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/main/java/mvm/rya/shell/util/JLinePrompt.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/main/java/mvm/rya/shell/util/JLinePrompt.java 
b/extras/rya.console/src/main/java/mvm/rya/shell/util/JLinePrompt.java
new file mode 100644
index 0000000..5af4278
--- /dev/null
+++ b/extras/rya.console/src/main/java/mvm/rya/shell/util/JLinePrompt.java
@@ -0,0 +1,200 @@
+/**
+ * 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 mvm.rya.shell.util;
+
+import static java.util.Objects.requireNonNull;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.util.FieldUtils;
+import org.springframework.shell.core.Shell;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+
+import jline.console.ConsoleReader;
+
+/**
+ * Provides access to the host {@link Shell}'s {@link ConsoleReader} and some
+ * utility functions for using it.
+ */
+@ParametersAreNonnullByDefault
+public abstract class JLinePrompt {
+
+    /**
+     * Defines things that may be typed in response to a boolean prompt that 
evaluate to true.
+     */
+    private static final Set<String> affirmativeStrings = 
Sets.newHashSet("true", "t", "yes", "y");
+
+    /**
+     * Defines things that may be typed in response to a boolean prompt that 
evaluate to false.
+     */
+    private static final Set<String> negativeStrings = 
Sets.newHashSet("false", "f", "no", "n");
+
+    @Autowired
+    private Shell shell;
+
+    /**
+     * @return The shell's {@link ConsoleReader}.
+     */
+    public ConsoleReader getReader() {
+        // XXX Spring Shell doesn't expose the reader that we need to use to
+        //     read values from a terminal, so use reflection to pull it out.
+        return (ConsoleReader) FieldUtils.getProtectedFieldValue("reader", 
shell);
+    }
+
+    /**
+     * Formats a prompt that shows a default value.
+     *
+     * @param fieldName - The text portion that appears before the default. 
(not null)
+     * @param defaultValue - The default value that will be shown in the 
prompt.
+     * @return A prompt that shows the default value for a field.
+     */
+    public String makeFieldPrompt(final String fieldName, final boolean 
defaultValue) {
+        return String.format("%s [default: %s]: ", fieldName, defaultValue);
+    }
+
+    /**
+     * Checks if a user's input matches one of the affirmative strings.
+     *
+     * @param input - The user's input. (not null)
+     * @return {@code true} if the input is one of the affirmative values; 
otherwise {@code false}.
+     */
+    private boolean isAffirmative(final String input) {
+        requireNonNull(input);
+        for(final String affirmativeString : affirmativeStrings) {
+            if( input.equalsIgnoreCase(affirmativeString) ) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks if a user's input matches one of the negative strings.
+     *
+     * @param input - The user's input. (not null)
+     * @return {@code true} if the input is one of the negative values; 
otherwise {@code false}.
+     */
+    private boolean isNegative(final String input) {
+        requireNonNull(input);
+        for(final String negativeString : negativeStrings) {
+            if( input.equalsIgnoreCase(negativeString) ) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Prompts a user for a boolean value. The prompt will be repeated until
+     * a value true/false string has been submitted. If a default value is
+     * provided, then it will be used if the user doens't enter anything.
+     *
+     * @param prompt - The prompt for the input. (not null)
+     * @param defaultValue - The default value for the input if one is 
provided. (not null)
+     * @return The value the user entered.
+     * @throws IOException There was a problem reading values from the user.
+     */
+    protected boolean promptBoolean(final String prompt, final 
Optional<Boolean> defaultValue) throws IOException {
+        requireNonNull(prompt);
+        requireNonNull(defaultValue);
+
+        final ConsoleReader reader = getReader();
+        reader.setPrompt(prompt);
+
+        Boolean value = null;
+        boolean prompting = true;
+
+        while(prompting) {
+            // An empty input means to use the default value.
+            final String input = reader.readLine();
+            if(input.isEmpty() && defaultValue.isPresent()) {
+                value = defaultValue.get();
+                prompting = false;
+            }
+
+            // Check if it is one of the affirmative answers.
+            if(isAffirmative(input)) {
+                value = true;
+                prompting = false;
+            }
+
+            // Check if it is one of the negative answers.
+            if(isNegative(input)) {
+                value = false;
+                prompting = false;
+            }
+
+            // If we are still prompting, the input was invalid.
+            if(prompting) {
+                reader.println("Invalid response (true/false)");
+            }
+        }
+
+        return value;
+    }
+
+    /**
+     * Prompts a user for a String value. The prompt will be repeated until a
+     * value has been submitted. If a default value is provided, then it will 
be
+     * used if the user doesn't enter anything.
+     *
+     * @param prompt - The prompt for the input. (not null)
+     * @param defaultValue - The default value for the input if one is 
provided. (not null)
+     * @return The value the user entered.
+     * @throws IOException There was a problem reading values from the user.
+     */
+    protected String promptString(final String prompt, final Optional<String> 
defaultValue) throws IOException {
+        requireNonNull(prompt);
+        requireNonNull(defaultValue);
+
+        final ConsoleReader reader = getReader();
+        reader.setPrompt(prompt);
+
+        String value = null;
+        boolean prompting = true;
+
+        while(prompting) {
+            // Read a line of input.
+            final String input = reader.readLine();
+
+            if(!input.isEmpty()) {
+                // If a value was provided, return it.
+                value = input;
+                prompting = false;
+            } else {
+                // Otherwise, if a default value was provided, return it;
+                if(defaultValue.isPresent()) {
+                    value = defaultValue.get();
+                    prompting = false;
+                } else {
+                    // Otherwise, the user must provide a value.
+                    reader.println("Invalid response. Must provide a value.");
+                }
+            }
+        }
+
+        return value;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/main/java/mvm/rya/shell/util/PasswordPrompt.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/main/java/mvm/rya/shell/util/PasswordPrompt.java 
b/extras/rya.console/src/main/java/mvm/rya/shell/util/PasswordPrompt.java
new file mode 100644
index 0000000..c4a7d90
--- /dev/null
+++ b/extras/rya.console/src/main/java/mvm/rya/shell/util/PasswordPrompt.java
@@ -0,0 +1,71 @@
+/**
+ * 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 mvm.rya.shell.util;
+
+import java.io.IOException;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import jline.console.ConsoleReader;
+
+/**
+ * A mechanism for prompting a user of the application for a password.
+ */
+@ParametersAreNonnullByDefault
+public interface PasswordPrompt {
+
+    /**
+     * Prompt the user for a password, wait for their input, and then get the
+     * value they entered.
+     *
+     * @return A character array holding the entered password.
+     * @throws IOEXception There was a problem reading the password.
+     */
+    public char[] getPassword() throws IOException;
+
+    /**
+     * Prompts a user for their password using a JLine {@link ConsoleReader}.
+     * <p>
+     * This prompt has a known security issue. ConsoleReader only reads 
passwords
+     * into Strings, so they can't easily be cleared out. We many an attempt to
+     * garbage collect the String after converting it to a character array, but
+     * this could be improved.
+     */
+    public static class JLinePasswordPrompt extends JLinePrompt implements 
PasswordPrompt {
+
+        @Override
+        public char[] getPassword() throws IOException {
+            char[] password = new char[0];
+
+            final ConsoleReader reader = getReader();
+            reader.setPrompt("Password: ");
+            String passwordStr = reader.readLine('*');
+            password = passwordStr.toCharArray();
+
+            // Reading the password into memory as a String is less safe than 
a char[]
+            // because the String is immutable. We can't clear it out. At 
best, we can
+            // remove all references to it and suggest the GC clean it up. 
There are no
+            // guarantees though.
+            passwordStr = null;
+            System.gc();
+
+            return password;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/main/java/mvm/rya/shell/util/RyaDetailsFormatter.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/main/java/mvm/rya/shell/util/RyaDetailsFormatter.java 
b/extras/rya.console/src/main/java/mvm/rya/shell/util/RyaDetailsFormatter.java
new file mode 100644
index 0000000..4c83b8d
--- /dev/null
+++ 
b/extras/rya.console/src/main/java/mvm/rya/shell/util/RyaDetailsFormatter.java
@@ -0,0 +1,117 @@
+/**
+ * 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 mvm.rya.shell.util;
+
+import static java.util.Objects.requireNonNull;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+
+import mvm.rya.api.instance.RyaDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails;
+
+/**
+ * Formats an instance of {@link RyaDetails}.
+ */
+@ParametersAreNonnullByDefault
+public class RyaDetailsFormatter {
+
+    /**
+     * Pretty formats an instance of {@link RyaDetails}.
+     *
+     * @param details - The object to format. (not null)
+     * @return A pretty render of the object.
+     */
+    public String format(final RyaDetails details) {
+        requireNonNull(details);
+
+        final StringBuilder report = new StringBuilder();
+
+        report.append("General Metadata:\n");
+        report.append("  Instance Name: 
").append(details.getRyaInstanceName()).append("\n");
+        report.append("  RYA Version: ").append( details.getRyaVersion() 
).append("\n");
+
+        report.append("Secondary Indicies:\n");
+        report.append("  Entity Centric Index:\n");
+        report.append("    Enabled: ").append( 
details.getEntityCentricIndexDetails().isEnabled() ).append("\n");
+        report.append("  Geospatial Index:\n");
+        report.append("    Enabled: ").append( 
details.getGeoIndexDetails().isEnabled() ).append("\n");
+        report.append("  Free Text Index:\n");
+        report.append("    Enabled: ").append( 
details.getFreeTextIndexDetails().isEnabled() ).append("\n");
+        report.append("  Temporal Index:\n");
+        report.append("    Enabled: ").append( 
details.getTemporalIndexDetails().isEnabled() ).append("\n");
+
+        report.append("  PCJ Index:\n");
+        final PCJIndexDetails pcjDetails = details.getPCJIndexDetails();
+        report.append("    Enabled: ").append( pcjDetails.isEnabled() 
).append("\n");
+        if(pcjDetails.isEnabled()) {
+            if(pcjDetails.getFluoDetails().isPresent()) {
+                final String fluoAppName = 
pcjDetails.getFluoDetails().get().getUpdateAppName();
+                report.append("    Fluo App Name: 
").append(fluoAppName).append("\n");
+            }
+
+            final ImmutableMap<String, PCJDetails> pcjs = 
pcjDetails.getPCJDetails();
+            report.append("    PCJs:\n");
+            if(pcjs.isEmpty()) {
+                report.append("      No PCJs have been added yet.\n");
+            } else {
+                for(final PCJDetails pcj : pcjs.values()) {
+                    report.append("      ID: 
").append(pcj.getId()).append("\n");
+
+                    final String updateStrategy = format( 
pcj.getUpdateStrategy(), "None" );
+                    report.append("        Update Strategy: 
").append(updateStrategy).append("\n");
+
+                    final String lastUpdateTime = format( 
pcj.getLastUpdateTime(), "unavailable");
+                    report.append("        Last Update Time: 
").append(lastUpdateTime).append("\n");
+                }
+            }
+        }
+
+        report.append("Statistics:\n");
+        report.append("  Prospector:\n");
+        final String prospectorLastUpdateTime = 
format(details.getProspectorDetails().getLastUpdated(), "unavailable");
+        report.append("    Last Update Time: ").append( 
prospectorLastUpdateTime).append("\n");
+
+        report.append("  Join Selectivity:\n");
+        final String jsLastUpdateTime = 
format(details.getJoinSelectivityDetails().getLastUpdated(), "unavailable");
+        report.append("    Last Updated Time: ").append( jsLastUpdateTime 
).append("\n");
+
+        return report.toString();
+    }
+
+    /**
+     * Formats an optional value using the value's toString() value.
+     *
+     * @param value - The optional value that will be formatted. (not null)
+     * @param absentValue - The String that will be returned if the optional 
is absent. (not null)
+     * @return The String representation of the optional value.
+     */
+    private <T> String format(final Optional<T> value, final String 
absentValue) {
+        requireNonNull(value);
+
+        String formatted = "unavailable";
+        if(value.isPresent()) {
+            formatted = value.get().toString();
+        }
+        return formatted;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/main/java/mvm/rya/shell/util/SparqlPrompt.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/main/java/mvm/rya/shell/util/SparqlPrompt.java 
b/extras/rya.console/src/main/java/mvm/rya/shell/util/SparqlPrompt.java
new file mode 100644
index 0000000..e47e292
--- /dev/null
+++ b/extras/rya.console/src/main/java/mvm/rya/shell/util/SparqlPrompt.java
@@ -0,0 +1,55 @@
+/**
+ * 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 mvm.rya.shell.util;
+
+import java.io.IOException;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import jline.console.ConsoleReader;
+
+/**
+ * A mechanism for prompting a user of the application for a SPARQL string.
+ */
+@ParametersAreNonnullByDefault
+public interface SparqlPrompt {
+
+    /**
+     * Prompt the user for a SPARQL query, wait for their input, and then get 
the
+     * value they entered.
+     *
+     * @return The user entered SPARQL query.
+     * @throws IOEXception There was a problem reading the user's input.
+     */
+    public String getSparql() throws IOException;
+
+    /**
+     * Prompts a user for a SPARQL query using a JLine {@link ConsoleReader}.
+     */
+    @ParametersAreNonnullByDefault
+    public static class JLineSparqlPrompt extends JLinePrompt implements 
SparqlPrompt {
+
+        @Override
+        public String getSparql() throws IOException {
+            final ConsoleReader reader = getReader();
+            reader.setPrompt("SPARQL: ");
+            return reader.readLine();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/main/resources/LICENSE.txt
----------------------------------------------------------------------
diff --git a/extras/rya.console/src/main/resources/LICENSE.txt 
b/extras/rya.console/src/main/resources/LICENSE.txt
new file mode 100644
index 0000000..4a9fe83
--- /dev/null
+++ b/extras/rya.console/src/main/resources/LICENSE.txt
@@ -0,0 +1,16 @@
+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.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/main/resources/META-INF/spring/spring-shell-plugin.xml
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/main/resources/META-INF/spring/spring-shell-plugin.xml 
b/extras/rya.console/src/main/resources/META-INF/spring/spring-shell-plugin.xml
index e593a48..b210311 100644
--- 
a/extras/rya.console/src/main/resources/META-INF/spring/spring-shell-plugin.xml
+++ 
b/extras/rya.console/src/main/resources/META-INF/spring/spring-shell-plugin.xml
@@ -1,30 +1,40 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
-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
+    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
 
-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.
--->
+        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.
+
+-->
 <beans xmlns="http://www.springframework.org/schema/beans";
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
        xmlns:context="http://www.springframework.org/schema/context";
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.1.xsd";>
 
-       <context:component-scan base-package="mvm.rya.console" />
+    <!-- Tell Spring where it can find all of the Command components. -->
+    <context:component-scan base-package="mvm.rya.shell"/>
 
-</beans>
+    <!-- Define the shell state bean that will be shared across all of the 
commands. -->
+    <bean id="sharedShellState" class="mvm.rya.shell.SharedShellState" />
+    <bean id="passwordPrompt" 
class="mvm.rya.shell.util.PasswordPrompt.JLinePasswordPrompt" />
+    <bean id="installPrompt" 
class="mvm.rya.shell.util.InstallPrompt.JLineAccumuloInstallPrompt" />
+    <bean id="sparqlPrompt" 
class="mvm.rya.shell.util.SparqlPrompt.JLineSparqlPrompt" />
+    
+    <!-- Define each of the beans that hold onto commands used by the shell. 
-->
+    <bean id="ryaConnectionCommands" 
class="mvm.rya.shell.RyaConnectionCommands" />
+    <bean id="ryaAdminCommands" class="mvm.rya.shell.RyaAdminCommands" />
+</beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/test/java/mvm/rya/shell/RyaAdminCommandsTest.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/test/java/mvm/rya/shell/RyaAdminCommandsTest.java 
b/extras/rya.console/src/test/java/mvm/rya/shell/RyaAdminCommandsTest.java
new file mode 100644
index 0000000..1baec41
--- /dev/null
+++ b/extras/rya.console/src/test/java/mvm/rya/shell/RyaAdminCommandsTest.java
@@ -0,0 +1,261 @@
+/**
+ * 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 mvm.rya.shell;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+
+import mvm.rya.api.client.RyaClientException;
+import mvm.rya.api.client.RyaClient;
+import mvm.rya.api.client.CreatePCJ;
+import mvm.rya.api.client.DeletePCJ;
+import mvm.rya.api.client.GetInstanceDetails;
+import mvm.rya.api.client.Install;
+import mvm.rya.api.client.InstanceDoesNotExistException;
+import mvm.rya.api.client.ListInstances;
+import mvm.rya.api.client.Install.DuplicateInstanceNameException;
+import mvm.rya.api.client.Install.InstallConfiguration;
+import mvm.rya.api.client.accumulo.AccumuloConnectionDetails;
+import mvm.rya.api.instance.RyaDetails;
+import mvm.rya.api.instance.RyaDetails.EntityCentricIndexDetails;
+import mvm.rya.api.instance.RyaDetails.FreeTextIndexDetails;
+import mvm.rya.api.instance.RyaDetails.GeoIndexDetails;
+import mvm.rya.api.instance.RyaDetails.JoinSelectivityDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.FluoDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails;
+import 
mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails.PCJUpdateStrategy;
+import mvm.rya.api.instance.RyaDetails.ProspectorDetails;
+import mvm.rya.api.instance.RyaDetails.TemporalIndexDetails;
+import mvm.rya.shell.util.InstallPrompt;
+import mvm.rya.shell.util.SparqlPrompt;
+
+/**
+ * Unit tests the methods of {@link RyaAdminCommands}.
+ */
+public class RyaAdminCommandsTest {
+
+    @Test
+    public void createPCJ() throws InstanceDoesNotExistException, 
RyaClientException, IOException {
+        // Mock the object that performs the create operation.
+        final String instanceName = "unitTest";
+        final String sparql = "SELECT * WHERE { ?person <http://isA> ?noun }";
+        final String pcjId = "123412342";
+        final CreatePCJ mockCreatePCJ = mock(CreatePCJ.class);
+        when(mockCreatePCJ.createPCJ( eq(instanceName), eq(sparql) ) 
).thenReturn( pcjId );
+
+        final RyaClient mockCommands = mock(RyaClient.class);
+        when(mockCommands.getCreatePCJ()).thenReturn( mockCreatePCJ );
+
+        final SharedShellState state = new SharedShellState();
+        state.connectedToAccumulo(mock(AccumuloConnectionDetails.class), 
mockCommands);
+        state.connectedToInstance(instanceName);
+
+        final SparqlPrompt mockSparqlPrompt = mock(SparqlPrompt.class);
+        when(mockSparqlPrompt.getSparql()).thenReturn(sparql);
+
+        // Execute the command.
+        final RyaAdminCommands commands = new RyaAdminCommands(state, 
mock(InstallPrompt.class), mockSparqlPrompt);
+        final String message = commands.createPcj();
+
+        // Verify the values that were provided to the command were passed 
through to CreatePCJ.
+        verify(mockCreatePCJ).createPCJ(eq(instanceName), eq(sparql));
+
+        // Verify a message is returned that explains what was created.
+        final String expected = "The PCJ has been created. Its ID is 
'123412342'.";
+        assertEquals(expected, message);
+    }
+
+    @Test
+    public void deletePCJ() throws InstanceDoesNotExistException, 
RyaClientException {
+        // Mock the object that performs the delete operation.
+        final DeletePCJ mockDeletePCJ = mock(DeletePCJ.class);
+
+        final RyaClient mockCommands = mock(RyaClient.class);
+        when(mockCommands.getDeletePCJ()).thenReturn( mockDeletePCJ );
+
+        final SharedShellState state = new SharedShellState();
+        state.connectedToAccumulo(mock(AccumuloConnectionDetails.class), 
mockCommands);
+        final String instanceName = "unitTests";
+        state.connectedToInstance(instanceName);
+
+        // Execute the command.
+        final String pcjId = "123412342";
+
+        final RyaAdminCommands commands = new RyaAdminCommands(state, 
mock(InstallPrompt.class), mock(SparqlPrompt.class));
+        final String message = commands.deletePcj(pcjId);
+
+        // Verify the values that were provided to the command were passed 
through to the DeletePCJ.
+        verify(mockDeletePCJ).deletePCJ(eq(instanceName), eq(pcjId));
+
+        // Verify a message is returned that explains what was deleted.
+        final String expected = "The PCJ has been deleted.";
+        assertEquals(expected, message);
+    }
+
+    @Test
+    public void getInstanceDetails() throws InstanceDoesNotExistException, 
RyaClientException {
+        // Mock the object that performs the get operation.
+        final GetInstanceDetails mockGetInstanceDetails = 
mock(GetInstanceDetails.class);
+        final String instanceName = "test_instance";
+        final RyaDetails details = 
RyaDetails.builder().setRyaInstanceName(instanceName)
+                .setRyaVersion("1.2.3.4")
+                .setEntityCentricIndexDetails( new 
EntityCentricIndexDetails(true) )
+                .setGeoIndexDetails( new GeoIndexDetails(true) )
+                .setTemporalIndexDetails( new TemporalIndexDetails(true) )
+                .setFreeTextDetails( new FreeTextIndexDetails(true) )
+                .setPCJIndexDetails(
+                        PCJIndexDetails.builder()
+                            .setEnabled(true)
+                            .setFluoDetails( new 
FluoDetails("test_instance_rya_pcj_updater") )
+                            .addPCJDetails(
+                                    PCJDetails.builder()
+                                        .setId("pcj 1")
+                                        
.setUpdateStrategy(PCJUpdateStrategy.BATCH)
+                                        .setLastUpdateTime( new 
Date(1252521351L) ))
+                            .addPCJDetails(
+                                    PCJDetails.builder()
+                                        .setId("pcj 2")
+                                        
.setUpdateStrategy(PCJUpdateStrategy.INCREMENTAL)))
+                .setProspectorDetails( new ProspectorDetails(Optional.of(new 
Date(12525211L))) )
+                .setJoinSelectivityDetails( new 
JoinSelectivityDetails(Optional.of(new Date(125221351L))) )
+                .build();
+
+        when(mockGetInstanceDetails.getDetails(eq(instanceName))).thenReturn( 
Optional.of(details) );
+
+        final RyaClient mockCommands = mock(RyaClient.class);
+        when(mockCommands.getGetInstanceDetails()).thenReturn( 
mockGetInstanceDetails );
+
+        final SharedShellState state = new SharedShellState();
+        state.connectedToAccumulo(mock(AccumuloConnectionDetails.class), 
mockCommands);
+        state.connectedToInstance(instanceName);
+
+        // Execute the command.
+        final RyaAdminCommands commands = new RyaAdminCommands(state, 
mock(InstallPrompt.class), mock(SparqlPrompt.class));
+        final String message = commands.getInstanceDetails();
+
+        // Verify the values that were provided to the command were passed 
through to the GetInstanceDetails.
+        verify(mockGetInstanceDetails).getDetails(eq(instanceName));
+
+        // Verify a message is returned that includes the details.
+        final String expected =
+                "General Metadata:\n" +
+                "  Instance Name: test_instance\n" +
+                "  RYA Version: 1.2.3.4\n" +
+                "Secondary Indicies:\n" +
+                "  Entity Centric Index:\n" +
+                "    Enabled: true\n" +
+                "  Geospatial Index:\n" +
+                "    Enabled: true\n" +
+                "  Free Text Index:\n" +
+                "    Enabled: true\n" +
+                "  Temporal Index:\n" +
+                "    Enabled: true\n" +
+                "  PCJ Index:\n" +
+                "    Enabled: true\n" +
+                "    Fluo App Name: test_instance_rya_pcj_updater\n" +
+                "    PCJs:\n" +
+                "      ID: pcj 1\n" +
+                "        Update Strategy: BATCH\n" +
+                "        Last Update Time: Thu Jan 15 06:55:21 EST 1970\n" +
+                "      ID: pcj 2\n" +
+                "        Update Strategy: INCREMENTAL\n" +
+                "        Last Update Time: unavailable\n" +
+                "Statistics:\n" +
+                "  Prospector:\n" +
+                "    Last Update Time: Wed Dec 31 22:28:45 EST 1969\n" +
+                "  Join Selectivity:\n" +
+                "    Last Updated Time: Fri Jan 02 05:47:01 EST 1970\n";
+        assertEquals(expected, message);
+    }
+
+    @Test
+    public void install() 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.connectedToAccumulo(mock(AccumuloConnectionDetails.class), 
mockCommands);
+
+        // Execute the command.
+        final String instanceName = "unitTests";
+        final InstallConfiguration installConfig = 
InstallConfiguration.builder()
+                .setEnableGeoIndex(true)
+                .setEnablePcjIndex(true)
+                .build();
+
+        final InstallPrompt mockInstallPrompt = mock(InstallPrompt.class);
+        when(mockInstallPrompt.promptInstanceName()).thenReturn( instanceName 
);
+        when(mockInstallPrompt.promptInstallConfiguration()).thenReturn( 
installConfig );
+        when(mockInstallPrompt.promptVerified(eq(instanceName), 
eq(installConfig))).thenReturn(true);
+
+        final RyaAdminCommands commands = new RyaAdminCommands(state, 
mockInstallPrompt, mock(SparqlPrompt.class));
+        final String message = commands.install();
+
+        // 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);
+        final List<String> instanceNames = Lists.newArrayList("a", "b", "c", 
"d");
+        when(mockListInstances.listInstances()).thenReturn(instanceNames);
+
+        final RyaClient mockCommands = mock(RyaClient.class);
+        when(mockCommands.getListInstances()).thenReturn( mockListInstances );
+
+        final SharedShellState state = new SharedShellState();
+        state.connectedToAccumulo(mock(AccumuloConnectionDetails.class), 
mockCommands);
+        state.connectedToInstance("b");
+
+        // Execute the command.
+        final RyaAdminCommands commands = new RyaAdminCommands(state, 
mock(InstallPrompt.class), mock(SparqlPrompt.class));
+        final String message = commands.listInstances();
+
+        // Verify a message is returned that lists the the instances.
+        final String expected =
+                "Rya instance names:\n" +
+                "   a\n" +
+                " * b\n" +
+                "   c\n" +
+                "   d\n";
+        assertEquals(expected, message);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/test/java/mvm/rya/shell/RyaConnectionCommandsIT.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/test/java/mvm/rya/shell/RyaConnectionCommandsIT.java 
b/extras/rya.console/src/test/java/mvm/rya/shell/RyaConnectionCommandsIT.java
new file mode 100644
index 0000000..c755181
--- /dev/null
+++ 
b/extras/rya.console/src/test/java/mvm/rya/shell/RyaConnectionCommandsIT.java
@@ -0,0 +1,269 @@
+/**
+ * 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.
+ */
+///**
+// * 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 mvm.rya.shell;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import org.apache.accumulo.minicluster.MiniAccumuloCluster;
+import org.junit.Test;
+import org.springframework.context.ApplicationContext;
+import org.springframework.shell.Bootstrap;
+import org.springframework.shell.core.CommandResult;
+import org.springframework.shell.core.JLineShellComponent;
+
+import mvm.rya.api.client.Install.InstallConfiguration;
+import mvm.rya.shell.SharedShellState.ConnectionState;
+import mvm.rya.shell.SharedShellState.ShellState;
+import mvm.rya.shell.util.InstallPrompt;
+import mvm.rya.shell.util.PasswordPrompt;
+
+/**
+ * Integration tests the methods of {@link RyaConnectionCommands}.
+ */
+public class RyaConnectionCommandsIT extends RyaShellITBase {
+
+    @Test
+    public void connectAccumulo() throws IOException {
+        final MiniAccumuloCluster cluster = getCluster();
+        final Bootstrap bootstrap = getTestBootstrap();
+        final JLineShellComponent shell = getTestShell();
+
+        // Mock the user entering the correct password.
+        final ApplicationContext context = bootstrap.getApplicationContext();
+        final PasswordPrompt mockPrompt = context.getBean( 
PasswordPrompt.class );
+        when(mockPrompt.getPassword()).thenReturn("password".toCharArray());
+
+        // Execute the connect command.
+        final String cmd =
+                RyaConnectionCommands.CONNECT_ACCUMULO_CMD + " " +
+                        "--username root " +
+                        "--instanceName " + cluster.getInstanceName() + " "+
+                        "--zookeepers " + cluster.getZooKeepers();
+
+        final CommandResult connectResult = shell.executeCommand(cmd);
+
+        // Ensure the connection was successful.
+        assertTrue( connectResult.isSuccess() );
+    }
+
+    @Test
+    public void connectAccumulo_noAuths() throws IOException {
+        final MiniAccumuloCluster cluster = getCluster();
+        final Bootstrap bootstrap = getTestBootstrap();
+        final JLineShellComponent shell = getTestShell();
+
+        // Mock the user entering the correct password.
+        final ApplicationContext context = bootstrap.getApplicationContext();
+        final PasswordPrompt mockPrompt = context.getBean( 
PasswordPrompt.class );
+        when(mockPrompt.getPassword()).thenReturn("password".toCharArray());
+
+        // Execute the command
+        final String cmd =
+                RyaConnectionCommands.CONNECT_ACCUMULO_CMD + " " +
+                        "--username root " +
+                        "--instanceName " + cluster.getInstanceName() + " "+
+                        "--zookeepers " + cluster.getZooKeepers();
+
+        final CommandResult connectResult = shell.executeCommand(cmd);
+
+        // Ensure the connection was successful.
+        assertTrue( connectResult.isSuccess() );
+    }
+
+    @Test
+    public void connectAccumulo_wrongCredentials() throws IOException {
+        final MiniAccumuloCluster cluster = getCluster();
+        final Bootstrap bootstrap = getTestBootstrap();
+        final JLineShellComponent shell = getTestShell();
+
+        // Mock the user entering the wrong password.
+        final ApplicationContext context = bootstrap.getApplicationContext();
+        final PasswordPrompt mockPrompt = context.getBean( 
PasswordPrompt.class );
+        when(mockPrompt.getPassword()).thenReturn("asjifo[ijwa".toCharArray());
+
+        // Execute the command
+        final String cmd =
+                RyaConnectionCommands.CONNECT_ACCUMULO_CMD + " " +
+                        "--username root " +
+                        "--instanceName " + cluster.getInstanceName() + " "+
+                        "--zookeepers " + cluster.getZooKeepers();
+
+        final CommandResult connectResult = shell.executeCommand(cmd);
+
+        // Ensure the command failed.
+        assertFalse( connectResult.isSuccess() );
+    }
+
+    @Test
+    public void printConnectionDetails_notConnected() {
+        final JLineShellComponent shell = getTestShell();
+
+        // Run the print connection details command.
+        final CommandResult printResult = shell.executeCommand( 
RyaConnectionCommands.PRINT_CONNECTION_DETAILS_CMD );
+        final String msg = (String) printResult.getResult();
+
+        final String expected = "The shell is not connected to anything.";
+        assertEquals(expected, msg);
+    }
+
+    @Test
+    public void printConnectionDetails_connectedToAccumulo() throws 
IOException {
+        final MiniAccumuloCluster cluster = getCluster();
+        final Bootstrap bootstrap = getTestBootstrap();
+        final JLineShellComponent shell = getTestShell();
+
+        // Mock the user entering the correct password.
+        final ApplicationContext context = bootstrap.getApplicationContext();
+        final PasswordPrompt mockPrompt = context.getBean( 
PasswordPrompt.class );
+        when(mockPrompt.getPassword()).thenReturn("password".toCharArray());
+
+        // Connect to the mini accumulo instance.
+        final String cmd =
+                RyaConnectionCommands.CONNECT_ACCUMULO_CMD + " " +
+                        "--username root " +
+                        "--instanceName " + cluster.getInstanceName() + " "+
+                        "--zookeepers " + cluster.getZooKeepers();
+        shell.executeCommand(cmd);
+
+        // Run the print connection details command.
+        final CommandResult printResult = shell.executeCommand( 
RyaConnectionCommands.PRINT_CONNECTION_DETAILS_CMD );
+        final String msg = (String) printResult.getResult();
+
+        final String expected =
+                "The shell is connected to an instance of Accumulo using the 
following parameters:\n" +
+                "    Username: root\n" +
+                "    Instance Name: " + cluster.getInstanceName() + "\n" +
+                "    Zookeepers: " + cluster.getZooKeepers();
+        assertEquals(expected, msg);
+    }
+
+    @Test
+    public void connectToInstance() throws IOException {
+        final MiniAccumuloCluster cluster = getCluster();
+        final Bootstrap bootstrap = getTestBootstrap();
+        final JLineShellComponent shell = getTestShell();
+
+        // Mock the user entering the correct password.
+        final ApplicationContext context = bootstrap.getApplicationContext();
+        final PasswordPrompt mockPrompt = context.getBean( 
PasswordPrompt.class );
+        when(mockPrompt.getPassword()).thenReturn("password".toCharArray());
+
+        // Connect to the mini accumulo instance.
+        String cmd =
+                RyaConnectionCommands.CONNECT_ACCUMULO_CMD + " " +
+                        "--username root " +
+                        "--instanceName " + cluster.getInstanceName() + " "+
+                        "--zookeepers " + cluster.getZooKeepers();
+        CommandResult result = shell.executeCommand(cmd);
+
+        // Install an instance of rya.
+        final String instanceName = "testInstance";
+        final InstallConfiguration installConf = 
InstallConfiguration.builder().build();
+
+        final InstallPrompt installPrompt = context.getBean( 
InstallPrompt.class );
+        when(installPrompt.promptInstanceName()).thenReturn("testInstance");
+        when(installPrompt.promptInstallConfiguration()).thenReturn( 
installConf );
+        when(installPrompt.promptVerified(instanceName, 
installConf)).thenReturn(true);
+
+        result = shell.executeCommand( RyaAdminCommands.INSTALL_CMD );
+        assertTrue( result.isSuccess() );
+
+        // Connect to the instance that was just installed.
+        cmd = RyaConnectionCommands.CONNECT_INSTANCE_CMD + " --instance " + 
instanceName;
+        result = shell.executeCommand(cmd);
+        assertTrue( result.isSuccess() );
+
+        // Verify the shell state indicates it is connected to an instance.
+        final SharedShellState sharedState = context.getBean( 
SharedShellState.class );
+        final ShellState state = sharedState.getShellState();
+        assertEquals(ConnectionState.CONNECTED_TO_INSTANCE, 
state.getConnectionState());
+    }
+
+    @Test
+    public void connectToInstance_instanceDoesNotExist() throws IOException {
+        final MiniAccumuloCluster cluster = getCluster();
+        final Bootstrap bootstrap = getTestBootstrap();
+        final JLineShellComponent shell = getTestShell();
+
+        // Mock the user entering the correct password.
+        final ApplicationContext context = bootstrap.getApplicationContext();
+        final PasswordPrompt mockPrompt = context.getBean( 
PasswordPrompt.class );
+        when(mockPrompt.getPassword()).thenReturn("password".toCharArray());
+
+        // Connect to the mini accumulo instance.
+        String cmd =
+                RyaConnectionCommands.CONNECT_ACCUMULO_CMD + " " +
+                        "--username root " +
+                        "--instanceName " + cluster.getInstanceName() + " "+
+                        "--zookeepers " + cluster.getZooKeepers();
+        shell.executeCommand(cmd);
+
+        // Try to connect to a non-existing instance.
+        cmd = RyaConnectionCommands.CONNECT_INSTANCE_CMD + " --instance 
doesNotExist";
+        final CommandResult result = shell.executeCommand(cmd);
+        assertFalse( result.isSuccess() );
+    }
+
+    @Test
+    public void disconnect() throws IOException {
+        final MiniAccumuloCluster cluster = getCluster();
+        final Bootstrap bootstrap = getTestBootstrap();
+        final JLineShellComponent shell = getTestShell();
+
+        // Mock the user entering the correct password.
+        final ApplicationContext context = bootstrap.getApplicationContext();
+        final PasswordPrompt mockPrompt = context.getBean( 
PasswordPrompt.class );
+        when(mockPrompt.getPassword()).thenReturn("password".toCharArray());
+
+        // Connect to the mini accumulo instance.
+        final String cmd =
+                RyaConnectionCommands.CONNECT_ACCUMULO_CMD + " " +
+                        "--username root " +
+                        "--instanceName " + cluster.getInstanceName() + " "+
+                        "--zookeepers " + cluster.getZooKeepers();
+        shell.executeCommand(cmd);
+
+        // Disconnect from it.
+        final CommandResult disconnectResult = shell.executeCommand( 
RyaConnectionCommands.DISCONNECT_COMMAND_NAME_CMD );
+        assertTrue( disconnectResult.isSuccess() );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/test/java/mvm/rya/shell/RyaPromptProviderTest.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/test/java/mvm/rya/shell/RyaPromptProviderTest.java 
b/extras/rya.console/src/test/java/mvm/rya/shell/RyaPromptProviderTest.java
new file mode 100644
index 0000000..54a0bba
--- /dev/null
+++ b/extras/rya.console/src/test/java/mvm/rya/shell/RyaPromptProviderTest.java
@@ -0,0 +1,80 @@
+/**
+ * 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 mvm.rya.shell;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import mvm.rya.api.client.RyaClient;
+import mvm.rya.api.client.accumulo.AccumuloConnectionDetails;
+
+/**
+ * Tests the methods of {@link RyaPromptProvider}.
+ */
+public class RyaPromptProviderTest {
+
+    @Test
+    public void notConnected() {
+        // Create a shared state that is disconnected.
+        final SharedShellState sharedState = new SharedShellState();
+        sharedState.disconnected();
+
+        // Create the prompt.
+        final String prompt = new RyaPromptProvider(sharedState).getPrompt();
+
+        // Verify the prompt is formatted correctly.
+        final String expected = "rya> ";
+        assertEquals(expected, prompt);
+    }
+
+    @Test
+    public void isConnected_noInstanceName() {
+        // Create a shared state that is connected to a storage, but not a rya 
instance.
+        final SharedShellState sharedState = new SharedShellState();
+
+        final AccumuloConnectionDetails connectionDetails = new 
AccumuloConnectionDetails("", new char[]{}, "testInstance", "");
+        sharedState.connectedToAccumulo(connectionDetails, 
mock(RyaClient.class));
+
+        // Create a prompt.
+        final String prompt = new RyaPromptProvider(sharedState).getPrompt();
+
+        // Verify the prompt is formatted correctly.
+        final String expected = "rya/testInstance> ";
+        assertEquals(expected, prompt);
+    }
+
+    @Test
+    public void isConnected_hasInstanceName() {
+        // Create a shared state that is connected to a specific instance.
+        final SharedShellState sharedState = new SharedShellState();
+
+        final AccumuloConnectionDetails connectionDetails = new 
AccumuloConnectionDetails("", new char[]{}, "testInstance", "");
+        sharedState.connectedToAccumulo(connectionDetails, 
mock(RyaClient.class));
+        sharedState.connectedToInstance("testRya");
+
+        // Create a prompt.
+        final String prompt = new RyaPromptProvider(sharedState).getPrompt();
+
+        // Verify the prompt is formatted correctly.
+        final String expected = "rya/testInstance:testRya> ";
+        assertEquals(expected, prompt);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/test/java/mvm/rya/shell/RyaShellITBase.java
----------------------------------------------------------------------
diff --git a/extras/rya.console/src/test/java/mvm/rya/shell/RyaShellITBase.java 
b/extras/rya.console/src/test/java/mvm/rya/shell/RyaShellITBase.java
new file mode 100644
index 0000000..162cecf
--- /dev/null
+++ b/extras/rya.console/src/test/java/mvm/rya/shell/RyaShellITBase.java
@@ -0,0 +1,103 @@
+/**
+ * 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 mvm.rya.shell;
+
+import java.io.IOException;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.minicluster.MiniAccumuloCluster;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.zookeeper.ClientCnxn;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.springframework.shell.Bootstrap;
+import org.springframework.shell.core.JLineShellComponent;
+
+import mvm.rya.accumulo.MiniAccumuloClusterInstance;
+
+/**
+ * All Rya Shell integration tests should extend this one. It provides startup
+ * and shutdown hooks for a Mini Accumulo Cluster when you start and stop 
testing.
+ * It also creates a new shell to test with between each test.
+ */
+public class RyaShellITBase {
+
+    /**
+     * The cluster that will be used.
+     */
+    private MiniAccumuloClusterInstance cluster = null;
+
+    /**
+     * The bootstrap that was used to initialize the Shell that will be tested.
+     */
+    private Bootstrap bootstrap;
+
+    /**
+     * The shell that will be tested.
+     */
+    private JLineShellComponent shell;
+
+    @BeforeClass
+    public static void killLoudLogs() {
+        Logger.getLogger(ClientCnxn.class).setLevel(Level.ERROR);
+    }
+
+    @Before
+    public void startShell() throws IOException, InterruptedException, 
AccumuloException, AccumuloSecurityException {
+        // Start the cluster.
+        cluster = new MiniAccumuloClusterInstance();
+        cluster.startMiniAccumulo();
+
+        // Bootstrap the shell with the test bean configuration.
+        bootstrap = new Bootstrap(new String[]{}, new 
String[]{"file:src/test/resources/RyaShellTest-context.xml"});
+        shell = bootstrap.getJLineShellComponent();
+    }
+
+    @After
+    public void stopShell() throws IOException, InterruptedException {
+        shell.stop();
+
+        // Stop the cluster.
+        cluster.stopMiniAccumulo();
+    }
+
+    /**
+     * @return The bootstrap that was used to initialize the Shell that will 
be tested.
+     */
+    public Bootstrap getTestBootstrap() {
+        return bootstrap;
+    }
+
+    /**
+     * @return The shell that will be tested.
+     */
+    public JLineShellComponent getTestShell() {
+        return shell;
+    }
+
+    /**
+     * @return The cluster that is hosting the test.
+     */
+    public MiniAccumuloCluster getCluster() {
+        return cluster.getCluster();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/test/java/mvm/rya/shell/SharedShellStateTest.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/test/java/mvm/rya/shell/SharedShellStateTest.java 
b/extras/rya.console/src/test/java/mvm/rya/shell/SharedShellStateTest.java
new file mode 100644
index 0000000..e5f0341
--- /dev/null
+++ b/extras/rya.console/src/test/java/mvm/rya/shell/SharedShellStateTest.java
@@ -0,0 +1,167 @@
+/**
+ * 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 mvm.rya.shell;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+
+import mvm.rya.api.client.RyaClient;
+import mvm.rya.api.client.accumulo.AccumuloConnectionDetails;
+import mvm.rya.shell.SharedShellState.ConnectionState;
+import mvm.rya.shell.SharedShellState.ShellState;
+
+/**
+ * Tests the methods of {@link SharedShellState}.
+ */
+public class SharedShellStateTest {
+
+    @Test
+    public void initialStateIsDisconnected() {
+        final SharedShellState state = new SharedShellState();
+
+        // Verify disconnected and no values are set.
+        final ShellState expected = ShellState.builder()
+                .setConnectionState(ConnectionState.DISCONNECTED)
+                .build();
+
+        assertEquals(expected, state.getShellState());
+    }
+
+    @Test
+    public void disconnectedToConnectedToStorage() {
+        final SharedShellState state = new SharedShellState();
+
+        // Connect to Accumulo.
+        final AccumuloConnectionDetails connectionDetails = 
mock(AccumuloConnectionDetails.class);
+        final RyaClient connectedCommands = mock(RyaClient.class);
+        state.connectedToAccumulo(connectionDetails, connectedCommands);
+
+        // Verify the state.
+        final ShellState expected = ShellState.builder()
+                .setConnectionState(ConnectionState.CONNECTED_TO_STORAGE)
+                .setAccumuloConnectionDetails(connectionDetails)
+                .setConnectedCommands(connectedCommands)
+                .build();
+
+        assertEquals(expected, state.getShellState());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void connectToStorageAgain() {
+        final SharedShellState state = new SharedShellState();
+
+        // Connect to Accumulo.
+        final AccumuloConnectionDetails connectionDetails = 
mock(AccumuloConnectionDetails.class);
+        final RyaClient connectedCommands = mock(RyaClient.class);
+        state.connectedToAccumulo(connectionDetails, connectedCommands);
+
+        // Try to set the information again.
+        state.connectedToAccumulo(connectionDetails, connectedCommands);
+    }
+
+    @Test
+    public void connectedToInstance() {
+        final SharedShellState state = new SharedShellState();
+
+        // Connect to Accumulo.
+        final AccumuloConnectionDetails connectionDetails = 
mock(AccumuloConnectionDetails.class);
+        final RyaClient connectedCommands = mock(RyaClient.class);
+        state.connectedToAccumulo(connectionDetails, connectedCommands);
+
+        // Connect to an Instance.
+        state.connectedToInstance("instance");
+
+        // Verify the state.
+        final ShellState expected = ShellState.builder()
+                .setConnectionState(ConnectionState.CONNECTED_TO_INSTANCE)
+                .setAccumuloConnectionDetails(connectionDetails)
+                .setConnectedCommands(connectedCommands)
+                .setRyaInstanceName("instance")
+                .build();
+
+        assertEquals(expected, state.getShellState());
+    }
+
+    @Test
+    public void ConnectedToInstanceAgain() {
+        final SharedShellState state = new SharedShellState();
+
+        // Connect to Accumulo.
+        final AccumuloConnectionDetails connectionDetails = 
mock(AccumuloConnectionDetails.class);
+        final RyaClient connectedCommands = mock(RyaClient.class);
+        state.connectedToAccumulo(connectionDetails, connectedCommands);
+
+        // Connect to an Instance.
+        state.connectedToInstance("instance");
+
+        // Connect to another instance.
+        state.connectedToInstance("secondInstance");
+
+        // Verify the state.
+        final ShellState expected = ShellState.builder()
+                .setConnectionState(ConnectionState.CONNECTED_TO_INSTANCE)
+                .setAccumuloConnectionDetails(connectionDetails)
+                .setConnectedCommands(connectedCommands)
+                .setRyaInstanceName("secondInstance")
+                .build();
+        assertEquals(expected, state.getShellState());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void connectedToInstanceWhileDisconnectedFromStorage() {
+        final SharedShellState state = new SharedShellState();
+
+        state.connectedToInstance("instance");
+    }
+
+    @Test
+    public void disconnected() {
+        final SharedShellState state = new SharedShellState();
+
+        // Connect to Accumulo and an instance.
+        final AccumuloConnectionDetails connectionDetails = 
mock(AccumuloConnectionDetails.class);
+        final RyaClient connectedCommands = mock(RyaClient.class);
+        state.connectedToAccumulo(connectionDetails, connectedCommands);
+        state.connectedToInstance("instance");
+
+        // Disconnect.
+        state.disconnected();
+
+        // Verify the state.
+        final ShellState expected = ShellState.builder()
+                .setConnectionState(ConnectionState.DISCONNECTED)
+                .build();
+        assertEquals(expected, state.getShellState());
+    }
+
+    @Test
+    public void disconnectedAgain() {
+        // Indicate we have diconnected while already in the disconnected 
state.
+        final SharedShellState state = new SharedShellState();
+        state.disconnected();
+
+        // Verify the state.
+        final ShellState expected = ShellState.builder()
+                .setConnectionState(ConnectionState.DISCONNECTED)
+                .build();
+        assertEquals(expected, state.getShellState());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/test/java/mvm/rya/shell/util/ConnectorFactoryIT.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/test/java/mvm/rya/shell/util/ConnectorFactoryIT.java 
b/extras/rya.console/src/test/java/mvm/rya/shell/util/ConnectorFactoryIT.java
new file mode 100644
index 0000000..e96b0ad
--- /dev/null
+++ 
b/extras/rya.console/src/test/java/mvm/rya/shell/util/ConnectorFactoryIT.java
@@ -0,0 +1,57 @@
+/**
+ * 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 mvm.rya.shell.util;
+
+import java.nio.CharBuffer;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.junit.Test;
+
+import mvm.rya.accumulo.AccumuloITBase;
+
+/**
+ * Tests the methods of {@link ConnectorFactory}.
+ */
+public class ConnectorFactoryIT extends AccumuloITBase {
+
+    @Test
+    public void connect_successful() throws AccumuloException, 
AccumuloSecurityException {
+        // Setup the values that will be tested with.
+        final CharSequence password = CharBuffer.wrap( getPassword() );
+
+        final ConnectorFactory ac = new ConnectorFactory();
+        ac.connect(getUsername(),
+                password,
+                getInstanceName(),
+                getZookeepers());
+    }
+
+    @Test(expected = AccumuloSecurityException.class)
+    public void connect_wrongCredentials() throws AccumuloException, 
AccumuloSecurityException {
+        // Setup the values that will be tested with.
+        final CharSequence password = CharBuffer.wrap( new char[] 
{'w','r','o','n','g','p','a','s','s'} );
+
+        final ConnectorFactory ac = new ConnectorFactory();
+        ac.connect(getUsername(),
+                password,
+                getInstanceName(),
+                getZookeepers());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/test/java/mvm/rya/shell/util/InstanceNamesFormatterTest.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/test/java/mvm/rya/shell/util/InstanceNamesFormatterTest.java
 
b/extras/rya.console/src/test/java/mvm/rya/shell/util/InstanceNamesFormatterTest.java
new file mode 100644
index 0000000..f10b776
--- /dev/null
+++ 
b/extras/rya.console/src/test/java/mvm/rya/shell/util/InstanceNamesFormatterTest.java
@@ -0,0 +1,81 @@
+/**
+ * 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 mvm.rya.shell.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import com.beust.jcommander.internal.Lists;
+
+/**
+ * Tests an instance of {@link InstanceNamesFormatter}.
+ */
+public class InstanceNamesFormatterTest {
+
+    @Test
+    public void format_withConnectedName() {
+        final List<String> instanceNames = Lists.newArrayList("a", "b", "c", 
"d");
+
+        final String formatted = new 
InstanceNamesFormatter().format(instanceNames, "c");
+
+        final String expected =
+                "Rya instance names:\n" +
+                "   a\n" +
+                "   b\n" +
+                " * c\n" +
+                "   d\n";
+
+        assertEquals(expected, formatted);
+    }
+
+    @Test
+    public void format_connectedNameNotInList() {
+        final List<String> instanceNames = Lists.newArrayList("a", "b", "c", 
"d");
+
+        final String formatted = new 
InstanceNamesFormatter().format(instanceNames, "not_in_list");
+
+        final String expected =
+                "Rya instance names:\n" +
+                "   a\n" +
+                "   b\n" +
+                "   c\n" +
+                "   d\n";
+
+        assertEquals(expected, formatted);
+    }
+
+    @Test
+    public void format() {
+        final List<String> instanceNames = Lists.newArrayList("a", "b", "c", 
"d");
+
+        final String formatted = new 
InstanceNamesFormatter().format(instanceNames);
+
+        final String expected =
+                "Rya instance names:\n" +
+                "   a\n" +
+                "   b\n" +
+                "   c\n" +
+                "   d\n";
+
+        assertEquals(expected, formatted);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/test/java/mvm/rya/shell/util/RyaDetailsFormatterTest.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.console/src/test/java/mvm/rya/shell/util/RyaDetailsFormatterTest.java
 
b/extras/rya.console/src/test/java/mvm/rya/shell/util/RyaDetailsFormatterTest.java
new file mode 100644
index 0000000..d618283
--- /dev/null
+++ 
b/extras/rya.console/src/test/java/mvm/rya/shell/util/RyaDetailsFormatterTest.java
@@ -0,0 +1,106 @@
+/**
+ * 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 mvm.rya.shell.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Date;
+
+import org.junit.Test;
+
+import com.google.common.base.Optional;
+
+import mvm.rya.api.instance.RyaDetails;
+import mvm.rya.api.instance.RyaDetails.EntityCentricIndexDetails;
+import mvm.rya.api.instance.RyaDetails.FreeTextIndexDetails;
+import mvm.rya.api.instance.RyaDetails.GeoIndexDetails;
+import mvm.rya.api.instance.RyaDetails.JoinSelectivityDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.FluoDetails;
+import mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails;
+import 
mvm.rya.api.instance.RyaDetails.PCJIndexDetails.PCJDetails.PCJUpdateStrategy;
+import mvm.rya.api.instance.RyaDetails.ProspectorDetails;
+import mvm.rya.api.instance.RyaDetails.TemporalIndexDetails;
+
+/**
+ * Tests the methods of {@link RyaDetailsFormatter}.
+ */
+public class RyaDetailsFormatterTest {
+
+    @Test
+    public void format() {
+        // Create the object that will be formatted.
+        final RyaDetails details = 
RyaDetails.builder().setRyaInstanceName("test_instance")
+            .setRyaVersion("1.2.3.4")
+            .setEntityCentricIndexDetails( new EntityCentricIndexDetails(true) 
)
+            .setGeoIndexDetails( new GeoIndexDetails(true) )
+            .setTemporalIndexDetails( new TemporalIndexDetails(true) )
+            .setFreeTextDetails( new FreeTextIndexDetails(true) )
+            .setPCJIndexDetails(
+                    PCJIndexDetails.builder()
+                        .setEnabled(true)
+                        .setFluoDetails( new 
FluoDetails("test_instance_rya_pcj_updater") )
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 1")
+                                    .setUpdateStrategy(PCJUpdateStrategy.BATCH)
+                                    .setLastUpdateTime( new Date(1252521351L) 
))
+                        .addPCJDetails(
+                                PCJDetails.builder()
+                                    .setId("pcj 2")
+                                    
.setUpdateStrategy(PCJUpdateStrategy.INCREMENTAL)))
+            .setProspectorDetails( new ProspectorDetails(Optional.of(new 
Date(12525211L))) )
+            .setJoinSelectivityDetails( new 
JoinSelectivityDetails(Optional.of(new Date(125221351L))) )
+            .build();
+
+        final String formatted = new RyaDetailsFormatter().format(details);
+
+        // Verify the created object matches the expected result.
+        final String expected =
+                "General Metadata:\n" +
+                "  Instance Name: test_instance\n" +
+                "  RYA Version: 1.2.3.4\n" +
+                "Secondary Indicies:\n" +
+                "  Entity Centric Index:\n" +
+                "    Enabled: true\n" +
+                "  Geospatial Index:\n" +
+                "    Enabled: true\n" +
+                "  Free Text Index:\n" +
+                "    Enabled: true\n" +
+                "  Temporal Index:\n" +
+                "    Enabled: true\n" +
+                "  PCJ Index:\n" +
+                "    Enabled: true\n" +
+                "    Fluo App Name: test_instance_rya_pcj_updater\n" +
+                "    PCJs:\n" +
+                "      ID: pcj 1\n" +
+                "        Update Strategy: BATCH\n" +
+                "        Last Update Time: Thu Jan 15 06:55:21 EST 1970\n" +
+                "      ID: pcj 2\n" +
+                "        Update Strategy: INCREMENTAL\n" +
+                "        Last Update Time: unavailable\n" +
+                "Statistics:\n" +
+                "  Prospector:\n" +
+                "    Last Update Time: Wed Dec 31 22:28:45 EST 1969\n" +
+                "  Join Selectivity:\n" +
+                "    Last Updated Time: Fri Jan 02 05:47:01 EST 1970\n";
+
+        assertEquals(expected, formatted);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.console/src/test/resources/RyaShellTest-context.xml
----------------------------------------------------------------------
diff --git a/extras/rya.console/src/test/resources/RyaShellTest-context.xml 
b/extras/rya.console/src/test/resources/RyaShellTest-context.xml
new file mode 100644
index 0000000..dfd075a
--- /dev/null
+++ b/extras/rya.console/src/test/resources/RyaShellTest-context.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns:context="http://www.springframework.org/schema/context";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
+               http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.1.xsd";>
+
+    <!-- Tell Spring where it can find all of the Command components. -->
+    <context:component-scan base-package="mvm.rya.shell"/>
+
+    <!-- Define the shell state bean that will be shared across all of the 
commands. -->
+    <bean id="sharedShellState" class="mvm.rya.shell.SharedShellState" />
+
+    <!-- We use a mock Password Prompt here to simulate a user entering a 
password. -->
+    <bean id="passwordPrompt" class="org.mockito.Mockito" 
factory-method="mock">
+        <constructor-arg value="mvm.rya.shell.util.PasswordPrompt" />
+    </bean>
+    
+    <!-- We use a mock Install Prompt here to simulate a user entering the 
installation configuration. -->
+    <bean id="installPrompt" class="org.mockito.Mockito" factory-method="mock">
+        <constructor-arg value="mvm.rya.shell.util.InstallPrompt"/>
+    </bean>
+
+    <!-- We use a mock SPARQL Prompt here to simulate a user entering the 
installation configuration. -->
+    <bean id="sparqlPrompt" class="org.mockito.Mockito" factory-method="mock">
+        <constructor-arg value="mvm.rya.shell.util.SparqlPrompt"/>
+    </bean>
+
+    <!-- Define each of the beans that hold onto commands used by the shell. 
-->
+    <bean id="ryaConnectionCommands" 
class="mvm.rya.shell.RyaConnectionCommands" />
+    <bean id="ryaAdminCommands" class="mvm.rya.shell.RyaAdminCommands" />
+</beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.indexing.pcj/pom.xml
----------------------------------------------------------------------
diff --git a/extras/rya.indexing.pcj/pom.xml b/extras/rya.indexing.pcj/pom.xml
index ee5ae07..c90ded3 100644
--- a/extras/rya.indexing.pcj/pom.xml
+++ b/extras/rya.indexing.pcj/pom.xml
@@ -43,6 +43,10 @@ under the License.
             <groupId>org.apache.rya</groupId>
             <artifactId>rya.api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.rya</groupId>
+            <artifactId>accumulo.rya</artifactId>
+        </dependency>
         
         <!-- Accumulo support dependencies. -->
         <dependency>
@@ -80,5 +84,11 @@ under the License.
             <artifactId>rya.sail</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.rya</groupId>
+            <artifactId>accumulo.rya</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+        </dependency>
     </dependencies>
 </project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.indexing.pcj/src/main/java/org/apache/rya/indexing/pcj/storage/PCJIdFactory.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.indexing.pcj/src/main/java/org/apache/rya/indexing/pcj/storage/PCJIdFactory.java
 
b/extras/rya.indexing.pcj/src/main/java/org/apache/rya/indexing/pcj/storage/PCJIdFactory.java
new file mode 100644
index 0000000..0bba346
--- /dev/null
+++ 
b/extras/rya.indexing.pcj/src/main/java/org/apache/rya/indexing/pcj/storage/PCJIdFactory.java
@@ -0,0 +1,34 @@
+/**
+ * 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.rya.indexing.pcj.storage;
+
+import java.util.UUID;
+
+/**
+ * Creates IDs for new Precomputed Joins.
+ */
+public class PCJIdFactory {
+
+    /**
+     * @return The next ID to use for a PCJ.
+     */
+    public String nextId() {
+        return UUID.randomUUID().toString().replaceAll("-", "");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/fcc98bd9/extras/rya.indexing.pcj/src/main/java/org/apache/rya/indexing/pcj/storage/PrecomputedJoinStorage.java
----------------------------------------------------------------------
diff --git 
a/extras/rya.indexing.pcj/src/main/java/org/apache/rya/indexing/pcj/storage/PrecomputedJoinStorage.java
 
b/extras/rya.indexing.pcj/src/main/java/org/apache/rya/indexing/pcj/storage/PrecomputedJoinStorage.java
index fb49b30..caaa8b6 100644
--- 
a/extras/rya.indexing.pcj/src/main/java/org/apache/rya/indexing/pcj/storage/PrecomputedJoinStorage.java
+++ 
b/extras/rya.indexing.pcj/src/main/java/org/apache/rya/indexing/pcj/storage/PrecomputedJoinStorage.java
@@ -19,13 +19,13 @@
 package org.apache.rya.indexing.pcj.storage;
 
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 
 import javax.annotation.ParametersAreNonnullByDefault;
 
-import org.apache.rya.indexing.pcj.storage.accumulo.VariableOrder;
 import org.apache.rya.indexing.pcj.storage.accumulo.VisibilityBindingSet;
+import org.openrdf.query.BindingSet;
 
 /**
  * Functions that create and maintain the PCJ tables that are used by Rya.
@@ -36,7 +36,7 @@ public interface PrecomputedJoinStorage {
     /**
      * Get a list of all Precomputed Join indices that are being maintained.
      *
-     * @return The lkist of managed Precomputed Join indices.
+     * @return The list of managed Precomputed Join IDs.
      */
     public List<String> listPcjs() throws PCJStorageException;
 
@@ -47,7 +47,7 @@ public interface PrecomputedJoinStorage {
      * @param varOrders - The variable orders the results within the table 
will be written to. (not null)
      * @return A unique identifier for the index.
      */
-    public String createPcj(final String sparql, final Set<VariableOrder> 
varOrders) throws PCJStorageException;
+    public String createPcj(final String sparql) throws PCJStorageException;
 
     /**
      * Get metadata about the Precomputed Join index.
@@ -67,6 +67,16 @@ public interface PrecomputedJoinStorage {
     public void addResults(final String pcjId, final 
Collection<VisibilityBindingSet> results) throws PCJStorageException;
 
     /**
+     * Get an {@link Iterator} over the {@link BindingSet}s that are stored in 
the PCJ table.
+     *
+     * @param pcjId - Identifies the index the results will be read from. (not 
null)
+     * @return An iterator over all of the {@link BindingSet}s that are stored 
as
+     *   results for the PCJ.
+     * @throws PCJStorageException The scan couldn't be performed.
+     */
+    public Iterable<BindingSet> listResults(String pcjId) throws 
PCJStorageException;
+
+    /**
      * Clears all values from a Precomputed Join index. The index will remain,
      * but all of its values will be removed.
      *

Reply via email to