2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org
.argeo
.jcr
;
19 import java
.lang
.reflect
.InvocationHandler
;
20 import java
.lang
.reflect
.Method
;
21 import java
.lang
.reflect
.Proxy
;
22 import java
.util
.ArrayList
;
23 import java
.util
.Collections
;
24 import java
.util
.List
;
26 import javax
.jcr
.Repository
;
27 import javax
.jcr
.RepositoryException
;
28 import javax
.jcr
.Session
;
29 import javax
.jcr
.SimpleCredentials
;
31 import org
.apache
.commons
.logging
.Log
;
32 import org
.apache
.commons
.logging
.LogFactory
;
33 import org
.argeo
.ArgeoException
;
34 import org
.springframework
.beans
.factory
.DisposableBean
;
35 import org
.springframework
.beans
.factory
.FactoryBean
;
37 /** Proxy JCR sessions and attach them to calling threads. */
38 public class ThreadBoundJcrSessionFactory
implements FactoryBean
,
40 private final static Log log
= LogFactory
41 .getLog(ThreadBoundJcrSessionFactory
.class);
43 private Repository repository
;
44 private List
<Session
> activeSessions
= Collections
45 .synchronizedList(new ArrayList
<Session
>());
47 private ThreadLocal
<Session
> session
= new ThreadLocal
<Session
>();
48 private boolean destroying
= false;
49 private final Session proxiedSession
;
51 private String defaultUsername
= "demo";
52 private String defaultPassword
= "demo";
54 public ThreadBoundJcrSessionFactory() {
55 Class
<?
>[] interfaces
= { Session
.class };
56 proxiedSession
= (Session
) Proxy
.newProxyInstance(getClass()
57 .getClassLoader(), interfaces
, new InvocationHandler() {
59 public Object
invoke(Object proxy
, Method method
, Object
[] args
)
61 Session threadSession
= session
.get();
62 if (threadSession
== null) {
63 if ("logout".equals(method
.getName()))// no need to login
65 threadSession
= login();
66 session
.set(threadSession
);
69 Object ret
= method
.invoke(threadSession
, args
);
70 if ("logout".equals(method
.getName())) {
73 activeSessions
.remove(threadSession
);
74 if (log
.isTraceEnabled())
75 log
.trace("Logged out from JCR session "
76 + threadSession
+ "; userId="
77 + threadSession
.getUserID());
84 protected Session
login() {
86 SimpleCredentials sc
= new SimpleCredentials(defaultUsername
,
87 defaultPassword
.toCharArray());
88 Session sess
= repository
.login(sc
);
89 if (log
.isTraceEnabled())
90 log
.trace("Log in to JCR session " + sess
+ "; userId="
92 // Thread.dumpStack();
93 activeSessions
.add(sess
);
95 } catch (RepositoryException e
) {
96 throw new ArgeoException("Cannot log in to repository", e
);
100 public Object
getObject() {
101 return proxiedSession
;
104 public void destroy() throws Exception
{
105 if (log
.isDebugEnabled())
106 log
.debug("Cleaning up " + activeSessions
.size()
107 + " active JCR sessions...");
110 for (Session sess
: activeSessions
) {
113 activeSessions
.clear();
116 public Class
<?
extends Session
> getObjectType() {
117 return Session
.class;
120 public boolean isSingleton() {
124 public void setRepository(Repository repository
) {
125 this.repository
= repository
;
128 public void setDefaultUsername(String defaultUsername
) {
129 this.defaultUsername
= defaultUsername
;
132 public void setDefaultPassword(String defaultPassword
) {
133 this.defaultPassword
= defaultPassword
;