/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.eclipse.ecr.core.api;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.ecr.core.api.impl.DocumentModelImpl;
import org.eclipse.ecr.core.api.repository.Repository;
import org.eclipse.ecr.core.api.repository.RepositoryManager;
import org.eclipse.ecr.core.schema.DocumentType;
import org.eclipse.ecr.runtime.api.Framework;
/**
* The CoreInstance is the main access point to a repository server.
* <p>
* A server instance is a singleton object that exists on each client JVM but
* also on the server JVM. The instance on the server JVM is used to access the
* server locally while those on client JVMs are used to access the server
* remotely.
* <p>
* A server instance uses a CoreSessionFactory to create CoreSession instances.
* CoreSessionFactory objects are implementation-dependent and may be registered
* using extension points. See {@link CoreSessionFactory} for more details.
* <p>
* Thus you can use a different implementation for the local ServerConnector
* than the one for the remote ServerConnector.
* <p>
* When clients need to perform a connection to a repository, they simply open a
* new session using the {@link CoreInstance#open(String, Map)} method.
* <p>
* When the client has done its work it <b>must</b> close its session by calling
* {@link CoreInstance#close(CoreSession)}.
* <p>
* This ensures correctly freeing all the resources held by the client session.
* <p>
* So a client session looks something like this:
* <p>
*
* <pre>
* <code>
* CoreInstance server = CoreInstance.getInstance();
* CoreSession client = server.open("demo", null);
* DocumentModel root = client.getRootDocument();
* // ... do something in that session ...
* // close the client -> this is closing the core session
* server.close(client);
* </code>
* </pre>
*
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*/
public class CoreInstance implements Serializable {
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(CoreInstance.class);
private static final CoreInstance instance = new CoreInstance();
private CoreSessionFactory factory;
private final Map<String, CoreSession> sessions = new ConcurrentHashMap<String, CoreSession>();
private final Map<String, DocumentType> docTypes = new Hashtable<String, DocumentType>();
// hiding the default constructor from clients
protected CoreInstance() {
}
/**
* Gets the CoreInstance singleton.
*
* @return the server instance
*/
public static CoreInstance getInstance() {
return instance;
}
public DocumentType getCachedDocumentType(String type) {
return docTypes.get(type);
}
public void cacheDocumentType(DocumentType docType) {
docTypes.put(docType.getName(), docType);
}
public CoreSession open(String repositoryName,
Map<String, Serializable> context) throws ClientException {
// instantiate a new client
try {
RepositoryManager rm = Framework.getService(RepositoryManager.class);
CoreSession session = null;
if (rm != null) {
Repository repo = rm.getRepository(repositoryName);
if (repo == null) {
throw new ClientException("No such repository: "
+ repositoryName);
}
// connect to the server
session = repo.open(context);
}
// ------ FIXME only for compat with tests ---
if (session == null) {
session = compatOpen(repositoryName, context);
}
// --------------------------------------------------------
return session;
} catch (Exception e) {
throw new ClientException(
"Failed to intialize core session on repository "
+ repositoryName, e);
}
}
/**
* Obsolete method only for compatibility with existing tests. Should be
* removed.
*
* @deprecated remove it
*/
@Deprecated
private CoreSession compatOpen(String repositoryName,
Map<String, Serializable> context) throws ClientException {
// instantiate a new client
CoreSession client = factory.getSession();
// connect to the server
client.connect(repositoryName, context);
// register the client locally
sessions.put(client.getSessionId(), client);
return client;
}
public void registerSession(String sid, CoreSession session) {
sessions.put(sid, session);
}
public CoreSession unregisterSession(String sid) {
return sessions.remove(sid);
}
public void close(CoreSession client) {
String sid = client.getSessionId();
if (sid == null) {
return; // session not yet connected
}
client = sessions.remove(sid);
if (client != null) {
client.destroy();
} else {
log.warn("Trying to close a non referenced CoreSession (destroy method won't be called)");
}
}
public boolean isSessionStarted(String sid) {
return sessions.containsKey(sid);
}
/** @deprecated unused */
@Deprecated
public CoreSession[] getSessions() {
Collection<CoreSession> valuesOfMap = sessions.values();
return valuesOfMap.toArray(new CoreSession[0]);
}
/**
* Gets the client bound to the given session.
*
* @param sid the session id
* @return the client
*/
public CoreSession getSession(String sid) {
HashMap<String, CoreSession> reentrantSession = DocumentModelImpl.reentrantCoreSession.get();
if (reentrantSession!=null && reentrantSession.containsKey(sid)) {
return reentrantSession.get(sid);
}
return sessions.get(sid);
}
public void initialize(CoreSessionFactory factory) {
// TODO: to be able to test more easily with a variety of client
// factories
// if (instance.factory == null) {
instance.factory = factory;
// }
}
public CoreSessionFactory getFactory() {
return factory;
}
}