/*
* 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:
* bstefanescu
*
* $Id$
*/
package org.eclipse.ecr.core.api.repository;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.ecr.core.api.CoreInstance;
import org.eclipse.ecr.core.api.CoreSession;
import org.eclipse.ecr.core.api.WrappedException;
import org.eclipse.ecr.runtime.api.Framework;
/**
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*/
public class RepositoryInstanceHandler implements InvocationHandler, RepositoryConnection, Serializable {
public static final Object NULL = new Object();
protected static final ConcurrentHashMap<Method, Method> methods = new ConcurrentHashMap<Method, Method>();
protected static ConcurrentHashMap<Method, MethodInvoker> invokers = new ConcurrentHashMap<Method, MethodInvoker>();
private static final long serialVersionUID = 1L;
protected final transient Repository repository;
protected final transient RepositoryExceptionHandler exceptionHandler;
protected transient CoreSession session;
protected transient RepositoryInstance proxy;
public RepositoryInstanceHandler(Repository repository, RepositoryExceptionHandler exceptionHandler) {
this.repository = repository;
this.exceptionHandler = exceptionHandler;
}
public RepositoryInstanceHandler(Repository repository) {
this(repository, null);
}
public RepositoryExceptionHandler getExceptionHandler() {
return exceptionHandler;
}
public RepositoryInstance getProxy() {
if (proxy == null) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
cl = Repository.class.getClassLoader();
}
proxy = (RepositoryInstance)Proxy.newProxyInstance(cl,
getProxyInterfaces(),
this);
}
return proxy;
}
public Class<?>[] getProxyInterfaces() {
return new Class[] { RepositoryInstance.class };
}
protected static void rethrowException(Throwable t) throws Exception {
if (t instanceof Exception) {
throw (Exception) t;
} else if (t instanceof Error) {
throw (Error) t;
} else {
throw WrappedException.wrap(t);
}
}
@Override
public Repository getRepository() {
return repository;
}
@Override
public CoreSession getSession() throws Exception {
if (session == null) {
synchronized (this) {
if (session == null) {
try {
open(repository);
} catch (Throwable t) {
if (exceptionHandler != null) {
session = exceptionHandler.handleAuthenticationFailure(repository, t);
} else {
rethrowException(t);
}
}
}
}
}
return session;
}
protected void open(Repository repository) throws Exception {
session = Framework.getService(CoreSession.class, repository.getName());
String repositoryUri = repository.getRepositoryUri();
if (repositoryUri == null) {
repositoryUri = repository.getName();
}
String sid = session.connect(repositoryUri, new HashMap<String, Serializable>());
// register session on local JVM so it can be used later by doc models
CoreInstance.getInstance().registerSession(sid, proxy);
}
@Override
public void close() throws Exception {
if (session != null) {
synchronized (this) {
if (session != null) {
try {
CoreInstance.getInstance().close(session);
} catch (Throwable t) {
if (exceptionHandler != null) {
exceptionHandler.handleException(t);
} else {
rethrowException(t);
}
} finally {
session = null;
}
}
}
}
}
@Override
@SuppressWarnings({"ObjectEquality"})
public synchronized Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
try {
// MethodInvoker invoker = invokers.get(method);
// if (invoker != null) {
// return invoker.invoke(this, method, args);
// } else if (method.getDeclaringClass() == CoreSession.class) {
// return method.invoke(getSession(), args);
// } else {
// return method.invoke(this, args);
// }
if (method.getDeclaringClass() == CoreSession.class) {
Method m = methods.get(method); // check if method was overwritten
if (m == null) {
try {
m = getClass().getMethod(method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException e) {
m = method;
}
methods.put(method, m);
}
return m.invoke(m == method ? getSession() : this, args);
}
return method.invoke(this, args);
} catch (InvocationTargetException e) {
// throw a ClientException
Throwable cause = e.getCause();
if (exceptionHandler != null) {
exceptionHandler.handleException(cause);
}
throw cause;
} catch (Throwable t) {
if (exceptionHandler != null) {
exceptionHandler.handleException(t);
}
throw t;
}
}
protected Object getImpl() {
return this;
}
public Object writeReplace() throws ObjectStreamException {
return Proxy.getInvocationHandler(session);
}
}