/*
- * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
+ * Copyright (C) 2007-2012 Mathieu Baudier
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.argeo.jcr;
import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.ArgeoException;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.FactoryBean;
-import org.springframework.beans.factory.InitializingBean;
/** Proxy JCR sessions and attach them to calling threads. */
-public class ThreadBoundJcrSessionFactory implements FactoryBean,
- InitializingBean, DisposableBean {
+public abstract class ThreadBoundJcrSessionFactory {
private final static Log log = LogFactory
.getLog(ThreadBoundJcrSessionFactory.class);
private Repository repository;
+ /** can be injected as list, only used if repository is null */
+ private List<Repository> repositories;
private ThreadLocal<Session> session = new ThreadLocal<Session>();
private final Session proxiedSession;
}
/** Logs in to the repository using various strategies. */
- protected Session login() {
- // discard sesison previoussly attached to this thread
+ protected synchronized Session login() {
+ if (!isActive())
+ throw new ArgeoException("Thread bound session factory inactive");
+
+ // discard session previously attached to this thread
Thread thread = Thread.currentThread();
if (activeSessions.containsKey(thread.getId())) {
Session oldSession = activeSessions.remove(thread.getId());
// Security)
if (!forceDefaultCredentials)
try {
- newSession = repository.login(workspace);
+ newSession = repository().login(workspace);
} catch (LoginException e1) {
log.warn("Cannot login without credentials: " + e1.getMessage());
// invalid credentials, go to the next step
try {
SimpleCredentials sc = new SimpleCredentials(defaultUsername,
defaultPassword.toCharArray());
- newSession = repository.login(sc, workspace);
+ newSession = repository().login(sc, workspace);
} catch (RepositoryException e) {
throw new ArgeoException("Cannot log in to repository", e);
}
return proxiedSession;
}
- public void afterPropertiesSet() throws Exception {
+ public void init() throws Exception {
monitoringThread = new MonitoringThread();
monitoringThread.start();
}
- public synchronized void destroy() throws Exception {
- if (log.isDebugEnabled())
- log.debug("Cleaning up " + activeSessions.size()
+ public synchronized void dispose() throws Exception {
+ if (activeSessions.size() == 0)
+ return;
+
+ if (log.isTraceEnabled())
+ log.trace("Cleaning up " + activeSessions.size()
+ " active JCR sessions...");
deactivate();
for (Session sess : activeSessions.values()) {
- sess.logout();
+ JcrUtils.logoutQuietly(sess);
}
activeSessions.clear();
- monitoringThread.join(1000);
}
protected Boolean isActive() {
notifyAll();
}
+ protected synchronized void removeSession(Thread thread) {
+ if (!isActive())
+ return;
+ activeSessions.remove(thread.getId());
+ threads.remove(thread);
+ }
+
+ protected synchronized void cleanDeadThreads() {
+ if (!isActive())
+ return;
+ Iterator<Thread> it = threads.iterator();
+ while (it.hasNext()) {
+ Thread thread = it.next();
+ if (!thread.isAlive() && isActive()) {
+ if (activeSessions.containsKey(thread.getId())) {
+ Session session = activeSessions.get(thread.getId());
+ activeSessions.remove(thread.getId());
+ session.logout();
+ if (log.isTraceEnabled())
+ log.trace("Cleaned up JCR session (userID="
+ + session.getUserID() + ") from dead thread "
+ + thread.getId());
+ }
+ it.remove();
+ }
+ }
+ try {
+ wait(1000);
+ } catch (InterruptedException e) {
+ // silent
+ }
+ }
+
public Class<? extends Session> getObjectType() {
return Session.class;
}
return session;
}
+ protected Repository repository() {
+ if (repository != null)
+ return repository;
+ if (repositories != null) {
+ // hardened for OSGi dynamic services
+ Iterator<Repository> it = repositories.iterator();
+ if (it.hasNext())
+ return it.next();
+ }
+ throw new ArgeoException("No repository injected");
+ }
+
+ // /** Useful for declarative registration of OSGi services (blueprint) */
+ // public void register(Repository repository, Map<?, ?> params) {
+ // this.repository = repository;
+ // }
+ //
+ // /** Useful for declarative registration of OSGi services (blueprint) */
+ // public void unregister(Repository repository, Map<?, ?> params) {
+ // this.repository = null;
+ // }
+
public void setRepository(Repository repository) {
this.repository = repository;
}
+ public void setRepositories(List<Repository> repositories) {
+ this.repositories = repositories;
+ }
+
public void setDefaultUsername(String defaultUsername) {
this.defaultUsername = defaultUsername;
}
protected class JcrSessionInvocationHandler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
+ throws Throwable, RepositoryException {
Session threadSession = session.get();
if (threadSession == null) {
if ("logout".equals(method.getName()))// no need to login
threadSession = login();
}
- Object ret = method.invoke(threadSession, args);
+ preCall(threadSession);
+ Object ret;
+ try {
+ ret = method.invoke(threadSession, args);
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof RepositoryException)
+ throw (RepositoryException) cause;
+ else
+ throw cause;
+ }
if ("logout".equals(method.getName())) {
- synchronized (ThreadBoundJcrSessionFactory.this) {
- session.remove();
- Thread thread = Thread.currentThread();
- if (isActive()) {
- activeSessions.remove(thread.getId());
- threads.remove(thread);
- }
- if (log.isTraceEnabled())
- log.trace("Logged out JCR session (userId="
- + threadSession.getUserID() + ") on thread "
- + thread.getId());
- }
+ session.remove();
+ Thread thread = Thread.currentThread();
+ removeSession(thread);
+ if (log.isTraceEnabled())
+ log.trace("Logged out JCR session (userId="
+ + threadSession.getUserID() + ") on thread "
+ + thread.getId());
}
return ret;
}
/** Monitors registered thread in order to clean up dead ones. */
private class MonitoringThread extends Thread {
+ public MonitoringThread() {
+ super("ThreadBound JCR Session Monitor");
+ }
+
@Override
public void run() {
while (isActive()) {
- Iterator<Thread> it = threads.iterator();
- while (it.hasNext()) {
- Thread thread = it.next();
- if (!thread.isAlive() && isActive()) {
- if (activeSessions.containsKey(thread.getId())) {
- Session session = activeSessions
- .get(thread.getId());
- activeSessions.remove(thread.getId());
- session.logout();
- if (log.isDebugEnabled())
- log.debug("Cleaned up JCR session (userID="
- + session.getUserID()
- + ") from dead thread "
- + thread.getId());
- }
- it.remove();
- }
- }
-
- synchronized (ThreadBoundJcrSessionFactory.this) {
- try {
- ThreadBoundJcrSessionFactory.this.wait(1000);
- } catch (InterruptedException e) {
- // silent
- }
- }
+ cleanDeadThreads();
}
}