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
.LoginException
;
27 import javax
.jcr
.Repository
;
28 import javax
.jcr
.RepositoryException
;
29 import javax
.jcr
.Session
;
30 import javax
.jcr
.SimpleCredentials
;
32 import org
.apache
.commons
.logging
.Log
;
33 import org
.apache
.commons
.logging
.LogFactory
;
34 import org
.argeo
.ArgeoException
;
35 import org
.springframework
.beans
.factory
.DisposableBean
;
36 import org
.springframework
.beans
.factory
.FactoryBean
;
38 /** Proxy JCR sessions and attach them to calling threads. */
39 public class ThreadBoundJcrSessionFactory
implements FactoryBean
,
41 private final static Log log
= LogFactory
42 .getLog(ThreadBoundJcrSessionFactory
.class);
44 private Repository repository
;
45 private List
<Session
> activeSessions
= Collections
46 .synchronizedList(new ArrayList
<Session
>());
48 private ThreadLocal
<Session
> session
= new ThreadLocal
<Session
>();
49 private boolean destroying
= false;
50 private final Session proxiedSession
;
52 private String defaultUsername
= "demo";
53 private String defaultPassword
= "demo";
54 private Boolean forceDefaultCredentials
= false;
56 public ThreadBoundJcrSessionFactory() {
57 Class
<?
>[] interfaces
= { Session
.class };
58 proxiedSession
= (Session
) Proxy
.newProxyInstance(getClass()
59 .getClassLoader(), interfaces
, new InvocationHandler() {
61 public Object
invoke(Object proxy
, Method method
, Object
[] args
)
63 Session threadSession
= session
.get();
64 if (threadSession
== null) {
65 if ("logout".equals(method
.getName()))// no need to login
67 threadSession
= login();
68 session
.set(threadSession
);
71 Object ret
= method
.invoke(threadSession
, args
);
72 if ("logout".equals(method
.getName())) {
75 activeSessions
.remove(threadSession
);
76 if (log
.isTraceEnabled())
77 log
.trace("Logged out from JCR session "
78 + threadSession
+ "; userId="
79 + threadSession
.getUserID());
86 protected Session
login() {
87 Session newSession
= null;
88 // first try to login without credentials, assuming the underlying login
89 // module will have dealt with authentication (typically using Spring
91 if (!forceDefaultCredentials
)
93 newSession
= repository
.login();
94 } catch (LoginException e1
) {
95 log
.warn("Cannot login without credentials: " + e1
.getMessage());
96 // invalid credentials, go to the next step
97 } catch (RepositoryException e1
) {
98 // other kind of exception, fail
99 throw new ArgeoException("Cannot log in to repository", e1
);
102 // log using default username / password (useful for testing purposes)
103 if (newSession
== null)
105 SimpleCredentials sc
= new SimpleCredentials(defaultUsername
,
106 defaultPassword
.toCharArray());
107 newSession
= repository
.login(sc
);
108 } catch (RepositoryException e
) {
109 throw new ArgeoException("Cannot log in to repository", e
);
112 // Log and monitor new session
113 if (log
.isTraceEnabled())
114 log
.trace("Logged in to JCR session " + newSession
+ "; userId="
115 + newSession
.getUserID());
116 activeSessions
.add(newSession
);
120 public Object
getObject() {
121 return proxiedSession
;
124 public void destroy() throws Exception
{
125 if (log
.isDebugEnabled())
126 log
.debug("Cleaning up " + activeSessions
.size()
127 + " active JCR sessions...");
130 for (Session sess
: activeSessions
) {
133 activeSessions
.clear();
136 public Class
<?
extends Session
> getObjectType() {
137 return Session
.class;
140 public boolean isSingleton() {
144 public void setRepository(Repository repository
) {
145 this.repository
= repository
;
148 public void setDefaultUsername(String defaultUsername
) {
149 this.defaultUsername
= defaultUsername
;
152 public void setDefaultPassword(String defaultPassword
) {
153 this.defaultPassword
= defaultPassword
;
156 public void setForceDefaultCredentials(Boolean forceDefaultCredentials
) {
157 this.forceDefaultCredentials
= forceDefaultCredentials
;