blob: 58bcfbe7c25787b42ee6d0d628b80573dbb247a6 [file] [log] [blame]
/**
* 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.shell;
import static java.util.Objects.requireNonNull;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.rya.api.client.RyaClient;
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.streams.api.RyaStreamsClient;
import com.google.common.base.Optional;
import com.mongodb.MongoClient;
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;
/**
* Holds values that are shared between the various Rya command classes.
*/
@ThreadSafe
@DefaultAnnotation(NonNull.class)
public class SharedShellState {
// The shared nature of this object means we shouldn't assume only a single thread is accessing it.
private final ReentrantLock lock = new ReentrantLock();
// The current state.
private ShellState shellState = ShellState.builder()
.setConnectionState( ConnectionState.DISCONNECTED )
.build();
/**
* @return The values that define the state of the Rya Shell.
*/
public ShellState getShellState() {
lock.lock();
try {
return shellState;
} finally {
lock.unlock();
}
}
/**
* This method indicates a shift into the {@link ConnectionState#CONNECTED_TO_STORAGE} state.
* <p/>
* Store the values used by an Accumulo Rya Storage connection. This may
* only be called when the shell is disconnected.
*
* @param connectionDetails - Metadata about the Accumulo connection. (not null)
* @param connectedCommands - Rya Commands that will execute against the Accumulo instance. (not null)
* @throws IllegalStateException Thrown if the shell is already connected to a Rya storage.
*/
public void connectedToAccumulo(
final AccumuloConnectionDetails 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 )
.setAccumuloDetails( connectionDetails )
.setConnectedCommands( connectedCommands )
.build();
} finally {
lock.unlock();
}
}
/**
* 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.
*
* @param instanceName - The name of the Rya instance. (not null)
* @throws IllegalStateException Thrown if the shell is disconnected.
*/
public void connectedToInstance(final String instanceName) throws IllegalStateException {
requireNonNull(instanceName);
lock.lock();
try {
// Verify the Rya Shell is connected to a storage.
if(shellState.getConnectionState() == ConnectionState.DISCONNECTED) {
throw new IllegalStateException("You can not set a Rya Instance Name before connecting to a Rya Storage.");
}
// Set the instance name.
shellState = ShellState.builder( shellState )
.setConnectionState(ConnectionState.CONNECTED_TO_INSTANCE)
.setRyaInstanceName( instanceName )
.build();
} finally {
lock.unlock();
}
}
/**
* This method indicates a shift into a state where the shell may have to interact with the Rya Streams subsystem.
* <p/>
* Stores the {@link RyaStreamsClient} all Rya Streams commands will be executed against.
*
* @param ryaStreamsCommands - Rya Streams commands that will execute against the Rya Streams subsystem. (not null)
*/
public void connectedToRyaStreams(
final RyaStreamsClient ryaStreamsCommands) {
requireNonNull(ryaStreamsCommands);
lock.lock();
try {
// Verify the Rya Shell is connected to an instance.
if(shellState.getConnectionState() != ConnectionState.CONNECTED_TO_INSTANCE) {
throw new IllegalStateException("You can not set the connected Rya Streams Client before connected to a Rya Instance.");
}
// Set the connected Rya Streams commands.
shellState = ShellState.builder( shellState )
.setRyaStreamsCommands(ryaStreamsCommands)
.build();
} finally {
lock.unlock();
}
}
/**
* This method indicates a shift into the {@link DISCONNECTED} state.
* <p/>
* Clears all of the values associated with a Rya Storage/Instance connection.
* If the shell is already disconnected, then this method does not do anything.
*/
public void disconnected() {
lock.lock();
try {
shellState = ShellState.builder()
.setConnectionState(ConnectionState.DISCONNECTED)
.build();
} finally {
lock.unlock();
}
}
/**
* Enumerates the various states a Rya Shell may be in.
*/
public static enum ConnectionState {
/**
* The shell is not connected to a Rya Storage.
*/
DISCONNECTED,
/**
* The shell is connected to a Rya Storage, but a specific instance hasn't been set.
*/
CONNECTED_TO_STORAGE,
/**
* The shell is connected to Rya Storage and a specific Rya Instance.
*/
CONNECTED_TO_INSTANCE;
}
/**
* 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
@DefaultAnnotation(NonNull.class)
public static final class ShellState {
// Indicates the state of the shell.
private final ConnectionState connectionState;
// Connection specific values.
private final Optional<StorageType> storageType;
private final Optional<AccumuloConnectionDetails> accumuloDetails;
private final Optional<MongoConnectionDetails> mongoDetails;
private final Optional<MongoClient> mongoAdminClient;
private final Optional<RyaClient> connectedCommands;
private final Optional<RyaStreamsClient> ryaStreamsCommands;
// Instance specific values.
private final Optional<String> instanceName;
private ShellState(
final ConnectionState connectionState,
final Optional<StorageType> storageType,
final Optional<AccumuloConnectionDetails> accumuloDetails,
final Optional<MongoConnectionDetails> mongoDetails,
final Optional<MongoClient> mongoAdminClient,
final Optional<RyaClient> connectedCommands,
final Optional<String> instanceName,
final Optional<RyaStreamsClient> ryaStreamsCommands) {
this.connectionState = requireNonNull(connectionState);
this.storageType = requireNonNull(storageType);
this.accumuloDetails = requireNonNull(accumuloDetails);
this.mongoDetails = requireNonNull(mongoDetails);
this.mongoAdminClient = requireNonNull(mongoAdminClient);
this.connectedCommands = requireNonNull(connectedCommands);
this.instanceName = requireNonNull(instanceName);
this.ryaStreamsCommands = requireNonNull(ryaStreamsCommands);
}
/**
* @return The {@link ConnectionState} of the Rya Shell.
*/
public ConnectionState getConnectionState() {
return connectionState;
}
/**
* @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 or is connected to another type
* of storage.
*/
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;
}
/**
* @return The Mongo Client that is used to perform administrative tasks while connected to Mongo DB.
*/
public Optional<MongoClient> getMongoAdminClient() {
return mongoAdminClient;
}
/**
* @return The {@link RyaClient} to use when a command on the shell is issued.
* The value will not be present if the Rya Shell is not connected to a storage.
*/
public Optional<RyaClient> getConnectedCommands() {
return connectedCommands;
}
/**
* @return The {@link RyaStreamsClient} to use when a command on the shell is issued.
* The value will not be present if the Rya Shell is not connected to an instance
* whose {@link RyaDetails} indicate when Rya Streams system to use.
*/
public Optional<RyaStreamsClient> getRyaStreamsCommands() {
return ryaStreamsCommands;
}
/**
* @return The name of the Rya Instance the Rya Shell is issuing commands to.
* The value will not be present if the Rya Shell is not connected to a
* storage or if a target instance has not been set yet.
*/
public Optional<String> getRyaInstanceName() {
return instanceName;
}
@Override
public int hashCode() {
return Objects.hash(connectionState, accumuloDetails, connectedCommands, instanceName);
}
@Override
public boolean equals(final Object obj) {
if(this == obj) {
return true;
}
if(obj instanceof ShellState) {
final ShellState state = (ShellState)obj;
return Objects.equals(connectionState, state.connectionState) &&
Objects.equals(accumuloDetails, state.accumuloDetails) &&
Objects.equals(connectedCommands, state.connectedCommands) &&
Objects.equals(instanceName, state.instanceName);
}
return false;
}
/**
* @return An empty instance of {@link Builder}.
*/
public static Builder builder() {
return new Builder();
}
/**
* Create an instance of {@link Builder} populated with the values of {code shellState}.
*
* @param shellState - The initial state of the Builder.
* @return An instance of {@link Builder} populated with the values
* of {code shellState}.
*/
public static Builder builder(final ShellState shellState) {
return new Builder(shellState);
}
/**
* Builds instances of {@link ShellState}.
*/
@DefaultAnnotation(NonNull.class)
public static class Builder {
private ConnectionState connectionState;
// Connection specific values.
private StorageType storageType;
private AccumuloConnectionDetails accumuloDetails;
private MongoConnectionDetails mongoDetails;
private MongoClient mongoAdminClient;
private RyaClient connectedCommands;
private RyaStreamsClient ryaStreamsCommands;
// Instance specific values.
private String instanceName;
/**
* Constructs an empty instance of {@link Builder}.
*/
public Builder() { }
/**
* Constructs an instance of {@builder} initialized with the values
* of a {@link ShellState}.
*
* @param shellState - The initial state of the builder. (not null)
*/
public Builder(final ShellState shellState) {
this.connectionState = shellState.getConnectionState();
this.storageType = shellState.getStorageType().orNull();
this.accumuloDetails = shellState.getAccumuloDetails().orNull();
this.mongoDetails = shellState.getMongoDetails().orNull();
this.mongoAdminClient = shellState.getMongoAdminClient().orNull();
this.connectedCommands = shellState.getConnectedCommands().orNull();
this.ryaStreamsCommands = shellState.getRyaStreamsCommands().orNull();
this.instanceName = shellState.getRyaInstanceName().orNull();
}
/**
* @param connectionState - The {@link ConnectionState} of the Rya Shell.
* @return This {@link Builder} so that method invocations may be chained.
*/
public Builder setConnectionState(@Nullable final ConnectionState connectionState) {
this.connectionState = connectionState;
return this;
}
/**
* @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 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;
}
/**
* @param mongoAdminClient - The Mongo Client that is used to perform administrative tasks while
* connected to Mongo DB.
* @return This {@link Builder} so that method invocations may be chained.
*/
public Builder setMongoAdminClient(@Nullable final MongoClient mongoAdminClient) {
this.mongoAdminClient = mongoAdminClient;
return this;
}
/**
* @param connectedCommands - The {@link RyaClient} to use when a command on the shell is issued.
* @return This {@link Builder} so that method invocations may be chained.
*/
public Builder setConnectedCommands(@Nullable final RyaClient connectedCommands) {
this.connectedCommands = connectedCommands;
return this;
}
/**
* @param ryaStreamsCommands - The {@link RyaStreamsClient} to use when a command on the shell is issued.
* @return This {@link Builder} so that method invocations may be chained.
*/
public Builder setRyaStreamsCommands(@Nullable final RyaStreamsClient ryaStreamsCommands) {
this.ryaStreamsCommands = ryaStreamsCommands;
return this;
}
/**
* @param instanceName - The name of the Rya Instance the Rya Shell is issuing commands to.
* @return This {@link Builder} so that method invocations may be chained.
*/
public Builder setRyaInstanceName(@Nullable final String instanceName) {
this.instanceName = instanceName;
return this;
}
/**
* @return An instance of {@link ShellState} built using this builder's values.
*/
public ShellState build() {
return new ShellState(
connectionState,
Optional.fromNullable(storageType),
Optional.fromNullable(accumuloDetails),
Optional.fromNullable(mongoDetails),
Optional.fromNullable(mongoAdminClient),
Optional.fromNullable(connectedCommands),
Optional.fromNullable(instanceName),
Optional.fromNullable(ryaStreamsCommands));
}
}
}
}