]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
144450c81712c4fffd23c8163ea5ceee09c296e4
[tmp/jakarta-migration.git] /
1 /*\r
2  * (C) Copyright 2006-2010 Nuxeo SAS (http://nuxeo.com/) and contributors.\r
3  *\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the GNU Lesser General Public License\r
6  * (LGPL) version 2.1 which accompanies this distribution, and is available at\r
7  * http://www.gnu.org/licenses/lgpl.html\r
8  *\r
9  * This library is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
12  * Lesser General Public License for more details.\r
13  *\r
14  * Contributors:\r
15  *     bstefanescu, jcarsique\r
16  *\r
17  * $Id$\r
18  */\r
19 \r
20 package org.collectionspace.services.nuxeo.client.java;\r
21 \r
22 import java.util.Collection;\r
23 import java.util.HashMap;\r
24 import java.util.Iterator;\r
25 import java.util.Map.Entry;\r
26 \r
27 import org.collectionspace.services.common.repository.RepositoryInstanceWrapperAdvice;\r
28 import org.collectionspace.services.config.tenant.RepositoryDomainType;\r
29 import org.jboss.remoting.InvokerLocator;\r
30 import org.nuxeo.ecm.core.api.repository.Repository;\r
31 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;\r
32 import org.nuxeo.ecm.core.api.repository.RepositoryInstanceHandler;\r
33 import org.nuxeo.ecm.core.api.repository.RepositoryManager;\r
34 import org.nuxeo.ecm.core.client.DefaultLoginHandler;\r
35 import org.nuxeo.ecm.core.client.LoginHandler;\r
36 import org.nuxeo.runtime.api.Framework;\r
37 import org.nuxeo.runtime.transaction.TransactionHelper;\r
38 \r
39 import javax.transaction.TransactionManager;\r
40 \r
41 import org.slf4j.Logger;\r
42 import org.slf4j.LoggerFactory;\r
43 import org.springframework.aop.framework.ProxyFactory;\r
44 \r
45 /**\r
46  * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>\r
47  *\r
48  */\r
49 public final class NuxeoClientEmbedded {\r
50 \r
51         private Logger logger = LoggerFactory.getLogger(NuxeoClientEmbedded.class);\r
52         \r
53     private LoginHandler loginHandler;\r
54 \r
55     private final HashMap<String, RepositoryInstanceInterface> repositoryInstances;\r
56 \r
57     private InvokerLocator locator;\r
58 \r
59     private RepositoryManager repositoryMgr;\r
60 \r
61     private static final NuxeoClientEmbedded instance = new NuxeoClientEmbedded();\r
62         \r
63     /**\r
64      * Constructs a new NuxeoClient. NOTE: Using {@link #getInstance()} instead\r
65      * of this constructor is recommended.\r
66      */\r
67     private NuxeoClientEmbedded() {\r
68         loginHandler = loginHandler == null ? new DefaultLoginHandler()\r
69                 : loginHandler;\r
70         repositoryInstances = new HashMap<String, RepositoryInstanceInterface>();\r
71     }\r
72     \r
73     public static NuxeoClientEmbedded getInstance() {\r
74         return instance;\r
75     }\r
76 \r
77     public synchronized void tryDisconnect() throws Exception {\r
78         if (locator == null) {\r
79             return; // do nothing\r
80         }\r
81         doDisconnect();\r
82     }\r
83 \r
84     private void doDisconnect() throws Exception {\r
85         locator = null;\r
86         // close repository sessions if any\r
87         Iterator<Entry<String, RepositoryInstanceInterface>> it = repositoryInstances.entrySet().iterator();\r
88         while (it.hasNext()) {\r
89             Entry<String, RepositoryInstanceInterface> repo = it.next();\r
90             try {\r
91                 repo.getValue().close();\r
92             } catch (Exception e) {\r
93                 logger.debug("Error while trying to close " + repo, e);\r
94             }\r
95             it.remove();\r
96         }\r
97 \r
98         repositoryMgr = null;\r
99     }\r
100 \r
101     public synchronized boolean isConnected() {\r
102         return true;\r
103     }\r
104 \r
105     public InvokerLocator getLocator() {\r
106         return locator;\r
107     }\r
108 \r
109     public synchronized LoginHandler getLoginHandler() {\r
110         return loginHandler;\r
111     }\r
112 \r
113     public synchronized void setLoginHandler(LoginHandler loginHandler) {\r
114         this.loginHandler = loginHandler;\r
115     }\r
116 \r
117     public RepositoryManager getRepositoryManager() throws Exception {\r
118         if (repositoryMgr == null) {\r
119             repositoryMgr = Framework.getService(RepositoryManager.class);\r
120         }\r
121         return repositoryMgr;\r
122     }\r
123 \r
124     /**\r
125      * Gets the repositories available on the connected server.\r
126      *\r
127      * @return the repositories\r
128      */\r
129     public Repository[] getRepositories() throws Exception {\r
130         Collection<Repository> repos = getRepositoryManager().getRepositories();\r
131         return repos.toArray(new Repository[repos.size()]);\r
132     }\r
133 \r
134     public Repository getDefaultRepository() throws Exception {\r
135         return getRepositoryManager().getDefaultRepository();\r
136     }\r
137 \r
138     public Repository getRepository(String name) throws Exception {\r
139         return getRepositoryManager().getRepository(name);\r
140     }\r
141 \r
142     /*\r
143      * Open a Nuxeo repo session using the passed in repoDomain and use the default tx timeout period\r
144      */\r
145     public RepositoryInstanceInterface openRepository(RepositoryDomainType repoDomain) throws Exception {\r
146         return openRepository(repoDomain.getRepositoryName(), -1);\r
147     }\r
148     \r
149     /*\r
150      * Open a Nuxeo repo session using the passed in repoDomain and use the default tx timeout period\r
151      */\r
152     public RepositoryInstanceInterface openRepository(String repoName) throws Exception {\r
153         return openRepository(repoName, -1);\r
154     }    \r
155 \r
156     public RepositoryInstanceInterface openRepository(String repoName, int timeoutSeconds) throws Exception {\r
157         RepositoryInstanceInterface result = null;\r
158         \r
159         //\r
160         // If the called passed in a custom timeout setting, use it to configure Nuxeo's transaction manager.\r
161         //\r
162         if (timeoutSeconds > 0) {\r
163                 TransactionManager transactionMgr = TransactionHelper.lookupTransactionManager();\r
164                 transactionMgr.setTransactionTimeout(timeoutSeconds);\r
165                 if (logger.isInfoEnabled()) {\r
166                         logger.info(String.format("Changing current request's transaction timeout period to %d seconds",\r
167                                         timeoutSeconds));\r
168                 }\r
169         }\r
170         \r
171         //\r
172         // Start a new Nuxeo transaction\r
173         //\r
174         boolean startedTransaction = false;\r
175         if (TransactionHelper.isTransactionActive() == false) {\r
176                 startedTransaction = TransactionHelper.startTransaction();\r
177                 if (startedTransaction == false) {\r
178                         String errMsg = "Could not start a Nuxeo transaction with the TransactionHelper class.";\r
179                         logger.error(errMsg);\r
180                         throw new Exception(errMsg);\r
181                 }\r
182         } else {\r
183                 logger.warn("A request to start a new transaction was made, but a transaction is already open.");\r
184         }\r
185         \r
186         //\r
187         // From the repository name that the caller passed in, get an instance of Nuxeo's Repository class.\r
188         // The Repository class is just a metadata description of the repository.\r
189         //\r
190         Repository repository;\r
191         if (repoName != null) {\r
192                 repository = getRepositoryManager().getRepository(repoName);\r
193         } else {\r
194                 repository = getRepositoryManager().getDefaultRepository();\r
195                 logger.warn(String.format("Using default repository '%s' because no name was specified.", repository.getName()));\r
196         }\r
197         \r
198         //\r
199         // Using the Repository class, get a Spring AOP proxied instance.  We use Spring AOP to "wrap" all calls to the\r
200         // Nuxeo repository so we can check for network related failures and perform a series of retries.\r
201         //\r
202         if (repository != null) {\r
203             result = getRepositoryInstanceWrapper(repository);\r
204                 logger.trace(String.format("A new transaction was started on thread '%d' : %s.",\r
205                                 Thread.currentThread().getId(), startedTransaction ? "true" : "false"));\r
206                 logger.trace(String.format("Added a new repository instance to our repo list.  Current count is now: %d",\r
207                                 repositoryInstances.size()));\r
208         } else {\r
209                 String errMsg = String.format("Could not open a session to the Nuxeo repository='%s'", repoName);\r
210                 logger.error(errMsg);\r
211                 throw new Exception(errMsg);\r
212         }       \r
213         \r
214         \r
215         return result;\r
216     }\r
217     \r
218     //\r
219     // Returns a proxied interface to a Nuxeo repository instance.  Our proxy uses Spring AOP to\r
220     // wrap each call to the Nuxeo repo with code that catches network related errors/exceptions and\r
221     // re-attempts the calls to see if it recovers.\r
222     //\r
223     private RepositoryInstanceInterface getAOPProxy(RepositoryInstance repositoryInstance) {\r
224         RepositoryInstanceInterface result = null;\r
225         \r
226         try {\r
227                         ProxyFactory factory = new ProxyFactory(new RepositoryInstanceWrapper(repositoryInstance));\r
228                         factory.addAdvice(new RepositoryInstanceWrapperAdvice());\r
229                         factory.setExposeProxy(true);\r
230                         result = (RepositoryInstanceInterface)factory.getProxy();\r
231         } catch (Exception e) {\r
232                 logger.error("Could not create AOP proxy for: " + RepositoryInstanceWrapper.class.getName(), e);\r
233         }\r
234         \r
235         return result;\r
236     }\r
237     \r
238     /*\r
239      * From the Repository object (a description of the repository), get repository instance wrapper.  Our wrapper\r
240      * will using the Spring AOP mechanism to intercept all calls to the repository.  We will wrap all the calls to the\r
241      * Nuxeo repository and check for network related failures.  We will retry all calls to the Nuxeo repo that fail because\r
242      * of network erros.\r
243      */\r
244     private RepositoryInstanceInterface getRepositoryInstanceWrapper(Repository repository) throws Exception {\r
245         RepositoryInstanceInterface result = null;\r
246                 \r
247         RepositoryInstance repositoryInstance = new RepositoryInstanceHandler(repository).getProxy();  // A Nuxeo repo instance handler proxy\r
248         if (repositoryInstance != null) {\r
249                 result = this.getAOPProxy(repositoryInstance);  // This is our AOP proxy\r
250                 if (result != null) {\r
251                         String key = result.getSessionId();\r
252                         repositoryInstances.put(key, result);\r
253                 } else {\r
254                         String errMsg = String.format("Could not instantiate a Spring AOP proxy for class '%s'.",\r
255                                         RepositoryInstanceWrapper.class.getName());\r
256                         logger.error(errMsg);\r
257                         throw new Exception(errMsg);\r
258                 }\r
259         } else {\r
260                 String errMsg = String.format("Could not create a new repository instance for '%s' repository.", repository.getName());\r
261                 logger.error(errMsg);\r
262                 throw new Exception(errMsg);\r
263         }\r
264         \r
265         return result;\r
266     }\r
267 \r
268     public void releaseRepository(RepositoryInstanceInterface repo) throws Exception {\r
269         String key = repo.getSessionId();\r
270 \r
271         try {\r
272                 repo.save();\r
273             repo.close();\r
274         } catch (Exception e) {\r
275                 logger.error("Possible data loss.  Could not save and/or release the repository.", e);\r
276                 throw e;\r
277         } finally {\r
278             RepositoryInstanceInterface wasRemoved = repositoryInstances.remove(key);\r
279             if (logger.isTraceEnabled()) {\r
280                 if (wasRemoved != null) {\r
281                         logger.trace("Removed a repository instance from our repo list.  Current count is now: "\r
282                                         + repositoryInstances.size());\r
283                 } else {\r
284                         logger.trace("Could not remove a repository instance from our repo list.  Current count is now: "\r
285                                         + repositoryInstances.size());\r
286                 }\r
287             }\r
288             if (TransactionHelper.isTransactionActiveOrMarkedRollback() == true) {\r
289                 TransactionHelper.commitOrRollbackTransaction();\r
290                 logger.trace(String.format("Transaction closed on thread '%d'", Thread.currentThread().getId()));\r
291             }\r
292         }\r
293     }    \r
294 }\r