package fr.opensagres.mongodb.ide.core.model;
import java.io.IOException;
import java.io.Writer;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.MongoURI;
import com.mongodb.tools.shell.ShellCommandManager;
import fr.opensagres.mongodb.ide.core.IServerListener;
import fr.opensagres.mongodb.ide.core.ServerEvent;
import fr.opensagres.mongodb.ide.core.internal.ServerNotificationManager;
import fr.opensagres.mongodb.ide.core.internal.Trace;
import fr.opensagres.mongodb.ide.core.internal.settings.AbstractSettings;
import fr.opensagres.mongodb.ide.core.internal.settings.ServersConstants;
import fr.opensagres.mongodb.ide.core.utils.StringUtils;
public class Server extends TreeContainerNode<Server> implements
ISchedulingRule {
private final String id;
private String name;
private MongoURI mongoURI;
private String host;
private Integer port;
private ServerState serverState;
private MongoRuntime runtime;
private Mongo mongo;
private ServerNotificationManager notificationManager;
private Map dataCache = new HashMap();
private Database currentDatabase;
public Server(String name, MongoURI mongoURI) {
this(String.valueOf(System.currentTimeMillis()), name, mongoURI);
}
public Server(String id, String name, MongoURI mongoURI) {
this.id = id;
this.mongoURI = mongoURI;
setName(name);
this.serverState = ServerState.Stopped;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MongoURI getMongoURI() {
return mongoURI;
}
public String getHost() {
computeHostAndPortIfNeeded();
return host;
}
public Integer getPort() {
computeHostAndPortIfNeeded();
return port;
}
public String getDatabaseName() {
return mongoURI.getDatabase();
}
private void computeHostAndPortIfNeeded() {
if (host == null) {
// host + port
String hostAndPort = mongoURI.getHosts().get(0);
int index = hostAndPort.indexOf(":");
if (index > 0) {
host = hostAndPort.substring(0, index);
try {
port = Integer.parseInt(hostAndPort.substring(index + 1,
hostAndPort.length()));
} catch (Throwable e) {
Trace.trace(Trace.STRING_SEVERE, "Error parsing port", e);
}
} else {
host = hostAndPort;
port = null;
}
}
}
public String getUsername() {
return mongoURI.getUsername();
}
public void setUsername(String username) {
// TODO
}
public char[] getPassword() {
return mongoURI.getPassword();
}
public void setPassword(String password) {
// TODO
}
public String getLabel() {
return name + " [" + mongoURI + "] - " + serverState;
}
@Override
public NodeType getType() {
return NodeType.Server;
}
@Override
protected void doGetChildren() throws Exception {
if (isConnected()) {
Mongo mongo = getMongo();
String databaseName = getDatabaseName();
if (StringUtils.isEmpty(databaseName)) {
// Server connection doesn't contains database in the MongoURI
// Display list of DB (works only if there is admin privilege
// for this DB).
List<String> names = getShellCommandManager().showDbs(mongo);
for (String name : names) {
Database database = new Database(name);
super.addNode(database);
}
} else {
// Display just the database.
Database database = new Database(databaseName);
super.addNode(database);
}
}
}
public Mongo getMongo() throws UnknownHostException, MongoException {
if (mongo == null) {
mongo = getShellCommandManager().connect(mongoURI);
}
return mongo;
}
public void dispose() {
disposeMongo();
}
public void disposeMongo() {
ShellCommandManager.getInstance().disconnect(mongo);
mongo = null;
}
public ServerState getServerState() {
return serverState;
}
public void setServerState(ServerState serverState) {
this.serverState = serverState;
// remove tree item of the server node
clearNodes(true);
// fire events
fireServerStateChangeEvent();
if (serverState == ServerState.Stopped) {
// close mongo.
disposeMongo();
}
}
// public void start() throws Exception {
// if (Platform.hasServerLauncherManager()) {
// Platform.getServerLauncherManager().start(this);
// }
// }
//
// public void stop(boolean force) throws Exception {
// if (Platform.hasServerLauncherManager()) {
// Platform.getServerLauncherManager().stop(this, force);
// }
// }
public void setRuntime(MongoRuntime runtime) {
this.runtime = runtime;
}
public MongoRuntime getRuntime() {
return runtime;
}
public boolean hasRuntime() {
return runtime != null;
}
public <T> T getData(Class<T> key) {
return (T) dataCache.get(key);
}
public <T> void setData(T data) {
dataCache.put(data.getClass(), data);
}
/**
* Returns true if the server is in a state that it can be stopped.
*
* @return boolean
*/
// public IStatus canStop() {
// if (getServerState() == ServerState.Stopped
// || getServerState() == ServerState.Stopping
// || getServerState() == ServerState.Disconnected)
// return new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0,
// Messages.errorStopAlreadyStopped, null);
//
// return Status.OK_STATUS;
// }
/**
* Adds the given server state listener to this server. Once registered, a
* listener starts receiving notification of state changes to this server.
* The listener continues to receive notifications until it is removed. Has
* no effect if an identical listener is already registered.
*
* @param listener
* the server listener
* @see #removeServerListener(IServerListener)
*/
public void addServerListener(IServerListener listener) {
if (listener == null)
throw new IllegalArgumentException("Module cannot be null");
if (Trace.LISTENERS) {
Trace.trace(Trace.STRING_LISTENERS, "Adding server listener "
+ listener + " to " + this);
}
getServerNotificationManager().addListener(listener);
}
/**
* Adds the given server state listener to this server. Once registered, a
* listener starts receiving notification of state changes to this server.
* The listener continues to receive notifications until it is removed. Has
* no effect if an identical listener is already registered.
*
* @param listener
* the server listener
* @param eventMask
* the bit-wise OR of all event types of interest to the listener
* @see #removeServerListener(IServerListener)
*/
public void addServerListener(IServerListener listener, int eventMask) {
if (listener == null)
throw new IllegalArgumentException("Module cannot be null");
if (Trace.LISTENERS) {
Trace.trace(Trace.STRING_LISTENERS, "Adding server listener "
+ listener + " to " + this + " with eventMask " + eventMask);
}
getServerNotificationManager().addListener(listener, eventMask);
}
/**
* Removes the given server state listener from this server. Has no effect
* if the listener is not registered.
*
* @param listener
* the listener
* @see #addServerListener(IServerListener)
*/
public void removeServerListener(IServerListener listener) {
if (listener == null)
throw new IllegalArgumentException("Module cannot be null");
if (Trace.LISTENERS) {
Trace.trace(Trace.STRING_LISTENERS, "Removing server listener "
+ listener + " from " + this);
}
getServerNotificationManager().removeListener(listener);
}
/**
* Fire a server listener state change event.
*/
protected void fireServerStateChangeEvent() {
if (Trace.LISTENERS) {
Trace.trace(Trace.STRING_LISTENERS,
"->- Firing server state change event: " + getName() + ", "
+ getServerState() + " ->-");
}
if (notificationManager == null || notificationManager.hasNoListeners())
return;
getServerNotificationManager().broadcastChange(
new ServerEvent(ServerEvent.SERVER_CHANGE
| ServerEvent.STATE_CHANGE, this, getServerState()));
}
/**
* Fire a server listener saved change event.
*/
protected void fireServerSavedChangeEvent() {
if (Trace.LISTENERS) {
Trace.trace(Trace.STRING_LISTENERS,
"->- Firing server state change event: " + getName() + ", "
+ getServerState() + " ->-");
}
if (notificationManager == null || notificationManager.hasNoListeners())
return;
getServerNotificationManager().broadcastChange(
new ServerEvent(ServerEvent.SERVER_CHANGE
| ServerEvent.SERVER_SAVED, this, getServerState()));
}
/**
* Fire a server listener saved change event.
*/
protected void fireDatabaseCreatedChangeEvent(Database database) {
if (Trace.LISTENERS) {
Trace.trace(
Trace.STRING_LISTENERS,
"->- Firing database created change event: "
+ database.getName() + ", " + getServerState()
+ " ->-");
}
if (notificationManager == null || notificationManager.hasNoListeners())
return;
getServerNotificationManager().broadcastChange(
new ServerEvent(ServerEvent.DATABASE_CHANGE
| ServerEvent.DATABASE_CREATED, database));
}
protected void fireDatabaseDroppedChangeEvent(Database database) {
if (Trace.LISTENERS) {
Trace.trace(
Trace.STRING_LISTENERS,
"->- Firing database dropped change event: "
+ database.getName() + ", " + getServerState()
+ " ->-");
}
if (notificationManager == null || notificationManager.hasNoListeners())
return;
getServerNotificationManager().broadcastChange(
new ServerEvent(ServerEvent.DATABASE_CHANGE
| ServerEvent.DATABASE_DROPPED, database));
}
protected void fireCollectionCreatedChangeEvent(Collection collection) {
if (Trace.LISTENERS) {
Trace.trace(
Trace.STRING_LISTENERS,
"->- Firing collection created change event: "
+ collection.getName() + ", " + getServerState()
+ " ->-");
}
if (notificationManager == null || notificationManager.hasNoListeners())
return;
getServerNotificationManager().broadcastChange(
new ServerEvent(ServerEvent.COLLECTION_CHANGE
| ServerEvent.COLLECTION_CREATED, collection));
}
/**
* Returns the event notification manager.
*
* @return the notification manager
*/
private ServerNotificationManager getServerNotificationManager() {
if (notificationManager == null)
notificationManager = new ServerNotificationManager();
return notificationManager;
}
public boolean contains(ISchedulingRule rule) {
return rule instanceof Server;
}
public boolean isConflicting(ISchedulingRule rule) {
return this.equals(rule);
}
public int getStopTimeout() {
// TODO Auto-generated method stub
return 1;
}
public boolean isConnected() {
return serverState == ServerState.Started
|| serverState == ServerState.Connected;
}
// public void connect() throws UnknownHostException, MongoException {
// setServerState(ServerState.Connecting);
// // Try to connect
// // MongoDriverHelper.tryConnection(getMongo());
// // Connection is OK, update the server state as connected.
// setServerState(ServerState.Connected);
// }
// public void disconnect() {
// disposeMongo();
// setServerState(ServerState.Disconnected);
// }
public Database findDatabase(String databaseName) {
List<TreeSimpleNode> children = getChildren();
for (TreeSimpleNode child : children) {
if (NodeType.Database.equals(child.getType())) {
if (databaseName.equals(((Database) child).getName())) {
return (Database) child;
}
}
}
return null;
}
public void unlock() {
Mongo mongo = null;
try {
mongo = getMongo();
} catch (Throwable e) {
}
if (mongo != null) {
mongo.unlock();
}
}
public boolean isLocked() {
try {
Mongo mongo = getMongo();
return mongo.isLocked();
} catch (Throwable e) {
return false;
}
}
@Override
public ShellCommandManager getShellCommandManager() {
return ShellCommandManager.getInstance();
}
public void save(Writer writer) throws IOException {
writer.append("<");
writer.append(ServersConstants.SERVER_ELT);
AbstractSettings.writeAttr(ServersConstants.ID_ATTR, this.getId(),
writer);
AbstractSettings.writeAttr(ServersConstants.NAME_ATTR, this.getName(),
writer);
AbstractSettings.writeAttr(ServersConstants.MONGO_URI_ATTR, this
.getMongoURI().toString(), writer);
if (this.getRuntime() != null) {
AbstractSettings.writeAttr(ServersConstants.RUNTIME_ID_ATTR, this
.getRuntime().getId(), writer);
}
writer.append("/>");
fireServerSavedChangeEvent();
}
/**
* Select the given database and returns true if current database is not the
* same than the given database.
*
* @param database
* @return
*/
protected boolean selectDatabase(Database database) {
if (currentDatabase == null) {
currentDatabase = database;
return true;
}
boolean result = currentDatabase.getId().equals(database.getId());
currentDatabase = database;
return !result;
}
/**
* Create database.
*
* @param databaseName
* @return
* @throws UnknownHostException
* @throws MongoException
*/
public Database createDatabase(String databaseName)
throws UnknownHostException, MongoException {
Database database = new Database(databaseName);
database.setParent(this);
// call get collection names to register the database.
database.getDB().getCollectionNames();
addNode(database);
// Database is created fire events
fireDatabaseCreatedChangeEvent(database);
return database;
}
public void dropDatabase(Database database) throws UnknownHostException,
MongoException {
getShellCommandManager().dropDatabase(database.getDB());
// Database is created fire events
fireDatabaseDroppedChangeEvent(database);
}
public void deleteCollection(Collection collection) {
// TODO Auto-generated method stub
}
public Collection createCollection(Database database, String databaseName,
String collectionName) throws UnknownHostException, MongoException {
boolean newDatabase = database == null;
if (database == null) {
database = new Database(databaseName);
database.setParent(this);
}
DBObject options = new BasicDBObject();
getShellCommandManager().createCollection(database.getDB(),
collectionName, options);
// Database is created fire events
if (newDatabase) {
addNode(database);
fireDatabaseCreatedChangeEvent(database);
}
// Create collection
Collection collection = new Collection(collectionName);
database.getCollectionsCategory().addNode(collection);
// Database is created fire events
fireCollectionCreatedChangeEvent(collection);
return collection;
}
}