]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
121abc2d549226ee758f1a54b9c95fbff5b117f9
[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.List;\r
26 import java.util.Map;\r
27 import java.util.Map.Entry;\r
28 import java.util.Vector;\r
29 \r
30 import javax.security.auth.login.AppConfigurationEntry;\r
31 import javax.transaction.TransactionManager;\r
32 \r
33 import org.apache.commons.logging.Log;\r
34 import org.apache.commons.logging.LogFactory;\r
35 import org.collectionspace.services.config.tenant.RepositoryDomainType;\r
36 import org.jboss.remoting.InvokerLocator;\r
37 import org.nuxeo.common.collections.ListenerList;\r
38 import org.nuxeo.ecm.core.api.repository.Repository;\r
39 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;\r
40 import org.nuxeo.ecm.core.api.repository.RepositoryInstanceHandler;\r
41 import org.nuxeo.ecm.core.api.repository.RepositoryManager;\r
42 import org.nuxeo.ecm.core.client.ConnectionListener;\r
43 import org.nuxeo.ecm.core.client.DefaultLoginHandler;\r
44 import org.nuxeo.ecm.core.client.LoginHandler;\r
45 import org.nuxeo.ecm.core.repository.RepositoryDescriptor;\r
46 import org.nuxeo.ecm.core.schema.SchemaManager;\r
47 import org.nuxeo.ecm.core.schema.SchemaManagerImpl;\r
48 import org.nuxeo.ecm.core.schema.TypeProvider;\r
49 import org.nuxeo.runtime.api.Framework;\r
50 import org.nuxeo.runtime.api.ServiceDescriptor;\r
51 import org.nuxeo.runtime.api.ServiceManager;\r
52 import org.nuxeo.runtime.api.login.LoginComponent;\r
53 import org.nuxeo.runtime.api.login.LoginService;\r
54 import org.nuxeo.runtime.api.login.SecurityDomain;\r
55 import org.nuxeo.runtime.config.AutoConfigurationService;\r
56 import org.nuxeo.runtime.remoting.RemotingService;\r
57 import org.nuxeo.runtime.services.streaming.StreamingService;\r
58 import org.nuxeo.runtime.transaction.TransactionHelper;\r
59 import org.slf4j.Logger;\r
60 import org.slf4j.LoggerFactory;\r
61 \r
62 /**\r
63  * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>\r
64  *\r
65  */\r
66 public final class NuxeoClientEmbedded {\r
67 \r
68         private Logger logger = LoggerFactory.getLogger(NuxeoClientEmbedded.class);\r
69         \r
70     private LoginHandler loginHandler;\r
71 \r
72     private final HashMap<String, RepositoryInstance> repositoryInstances;\r
73 \r
74     private final ListenerList connectionListeners;\r
75 \r
76     private InvokerLocator locator;\r
77 \r
78     private String serverName;\r
79 \r
80     private final AutoConfigurationService cfg;\r
81 \r
82     private RepositoryManager repositoryMgr;\r
83 \r
84     private boolean multiThreadedLogin = false;\r
85 \r
86     private static final NuxeoClientEmbedded instance = new NuxeoClientEmbedded();\r
87 \r
88     private static final Log log = LogFactory.getLog(NuxeoClientEmbedded.class);\r
89 \r
90     /**\r
91      * Constructs a new NuxeoClient. NOTE: Using {@link #getInstance()} instead\r
92      * of this constructor is recommended.\r
93      */\r
94     public NuxeoClientEmbedded() {\r
95         connectionListeners = new ListenerList();\r
96         cfg = new AutoConfigurationService();\r
97         loginHandler = loginHandler == null ? new DefaultLoginHandler()\r
98                 : loginHandler;\r
99         repositoryInstances = new HashMap<String, RepositoryInstance>();\r
100     }\r
101 \r
102     public static NuxeoClientEmbedded getInstance() {\r
103         return instance;\r
104     }\r
105 \r
106     public void setMultiThreadedLogin(boolean useMultiThreadedLogin) {\r
107         multiThreadedLogin = useMultiThreadedLogin;\r
108     }\r
109 \r
110     public boolean getMultiThreadedLogin() {\r
111         return multiThreadedLogin;\r
112     }\r
113 \r
114     public synchronized void connect(String locator) throws Exception {\r
115         if (this.locator != null) {\r
116             throw new IllegalStateException("Client is already connected");\r
117         }\r
118         doConnect(AutoConfigurationService.createLocator(locator));\r
119     }\r
120 \r
121     public synchronized void connect(InvokerLocator locator) throws Exception {\r
122         if (this.locator != null) {\r
123             throw new IllegalStateException("Client is already connected");\r
124         }\r
125         doConnect(locator);\r
126     }\r
127 \r
128     public synchronized void connect(String host, int port) throws Exception {\r
129         if (locator != null) {\r
130             throw new IllegalStateException("Client is already connected");\r
131         }\r
132         doConnect(AutoConfigurationService.createLocator(host, port));\r
133     }\r
134 \r
135     public synchronized void forceConnect(InvokerLocator locator)\r
136             throws Exception {\r
137         if (this.locator != null) {\r
138             disconnect();\r
139         }\r
140         doConnect(locator);\r
141     }\r
142 \r
143     public synchronized void forceConnect(String locator) throws Exception {\r
144         if (this.locator != null) {\r
145             disconnect();\r
146         }\r
147         doConnect(AutoConfigurationService.createLocator(locator));\r
148     }\r
149 \r
150     public synchronized void forceConnect(String host, int port)\r
151             throws Exception {\r
152         if (locator != null) {\r
153             disconnect();\r
154         }\r
155         doConnect(AutoConfigurationService.createLocator(host, port));\r
156     }\r
157 \r
158     public synchronized void tryConnect(String host, int port) throws Exception {\r
159         if (locator != null) {\r
160             return; // do nothing\r
161         }\r
162         doConnect(AutoConfigurationService.createLocator(host, port));\r
163     }\r
164 \r
165     public synchronized void tryConnect(String url) throws Exception {\r
166         if (locator != null) {\r
167             return; // do nothing\r
168         }\r
169         doConnect(AutoConfigurationService.createLocator(url));\r
170     }\r
171 \r
172     public synchronized void tryConnect(InvokerLocator locator)\r
173             throws Exception {\r
174         if (this.locator != null) {\r
175             return; // do nothing\r
176         }\r
177         doConnect(locator);\r
178     }\r
179 \r
180     @Deprecated\r
181     private void doConnect(InvokerLocator locator) throws Exception {\r
182         this.locator = locator;\r
183         try {\r
184             cfg.load(locator);\r
185             // FIXME TODO workaround to work with nxruntime core 1.3.3\r
186             // --------------\r
187             String newPort = Framework.getProperty("org.nuxeo.runtime.1.3.3.streaming.port");\r
188             if (newPort != null) {\r
189                 StreamingService streamingService = (StreamingService) Framework.getRuntime().getComponent(\r
190                         StreamingService.NAME);\r
191                 // streaming config\r
192                 String oldLocator = streamingService.getServerLocator();\r
193                 int p = oldLocator.lastIndexOf(':');\r
194                 if (p > -1) {\r
195                     String withoutPort = oldLocator.substring(0, p);\r
196                     String serverLocator = withoutPort + ":" + newPort;\r
197                     streamingService.stopManager();\r
198                     streamingService.setServerLocator(serverLocator);\r
199                     streamingService.setServer(false);\r
200                     streamingService.startManager();\r
201                 }\r
202             }\r
203             // FIXME TODO workaround for remote services\r
204             // -------------------------------\r
205             schemaRemotingWorkaround(locator.getHost());\r
206             // workaround for client login configuration - we need to make it\r
207             // not multi threaded\r
208             // TODO put an option for this in NuxeoClient\r
209             if (!multiThreadedLogin) {\r
210                 LoginService ls = Framework.getService(LoginService.class);\r
211                 SecurityDomain sysDomain = ls.getSecurityDomain(LoginComponent.SYSTEM_LOGIN);\r
212                 SecurityDomain clientDomain = ls.getSecurityDomain(LoginComponent.CLIENT_LOGIN);\r
213                 adaptClientSecurityDomain(sysDomain);\r
214                 adaptClientSecurityDomain(clientDomain);\r
215             }\r
216             // ----------------\r
217 //            login();\r
218             if (!multiThreadedLogin) {\r
219                 throw new RuntimeException("This coode is dead and should never be called?"); //FIXME: REM - If you're reading this, this was left here by mistake and should be removed.\r
220             }\r
221         } catch (Exception e) {\r
222             this.locator = null;\r
223             throw e;\r
224         }\r
225         fireConnected(this);\r
226     }\r
227 \r
228     public static void adaptClientSecurityDomain(SecurityDomain sd) {\r
229         AppConfigurationEntry[] entries = sd.getAppConfigurationEntries();\r
230         if (entries != null) {\r
231             for (int i = 0; i < entries.length; i++) {\r
232                 AppConfigurationEntry entry = entries[i];\r
233                 if ("org.jboss.security.ClientLoginModule".equals(entry.getLoginModuleName())) {\r
234                     Map<String, ?> opts = entry.getOptions();\r
235                     Map<String, Object> newOpts = new HashMap<String, Object>(\r
236                             opts);\r
237                     newOpts.put("multi-threaded", "false");\r
238                     entries[i] = new AppConfigurationEntry(\r
239                             entry.getLoginModuleName(), entry.getControlFlag(),\r
240                             entry.getOptions());\r
241                 }\r
242             }\r
243         }\r
244     }\r
245 \r
246     /**\r
247      * Workaround for being able to load schemas from remote\r
248      * TODO integrate this in core\r
249      */\r
250     private static void schemaRemotingWorkaround(String host) throws Exception {\r
251         ServiceManager serviceManager = Framework.getLocalService(ServiceManager.class);\r
252         ServiceDescriptor sd = new ServiceDescriptor(TypeProvider.class, "core");\r
253         sd.setLocator("%TypeProviderBean");\r
254         serviceManager.registerService(sd);\r
255         TypeProvider typeProvider = Framework.getService(TypeProvider.class);\r
256         SchemaManager schemaMgr = Framework.getLocalService(SchemaManager.class);\r
257         ((SchemaManagerImpl) schemaMgr).importTypes(typeProvider);\r
258     }\r
259 \r
260     public synchronized void disconnect() throws Exception {\r
261         if (locator == null) {\r
262             throw new IllegalStateException("Client is not connected");\r
263         }\r
264         doDisconnect();\r
265     }\r
266 \r
267     public synchronized void tryDisconnect() throws Exception {\r
268         if (locator == null) {\r
269             return; // do nothing\r
270         }\r
271         doDisconnect();\r
272     }\r
273 \r
274     @Deprecated\r
275     private void doDisconnect() throws Exception {\r
276         locator = null;\r
277         serverName = null;\r
278         // close repository sessions if any\r
279         Iterator<Entry<String, RepositoryInstance>> it = repositoryInstances.entrySet().iterator();\r
280         while (it.hasNext()) {\r
281             Entry<String, RepositoryInstance> repo = it.next();\r
282             try {\r
283                 repo.getValue().close();\r
284             } catch (Exception e) {\r
285                 log.debug("Error while trying to close " + repo, e);\r
286             }\r
287             it.remove();\r
288         }\r
289         // logout\r
290 //        logout();\r
291         if (!multiThreadedLogin) {\r
292                 throw new RuntimeException("This coode is dead and should never be called?"); //FIXME: REM - If you're reading this, this was left here by mistake and should be removed.\r
293         }\r
294         repositoryMgr = null;\r
295         fireDisconnected(this);\r
296     }\r
297 \r
298     public synchronized void reconnect() throws Exception {\r
299         if (locator == null) {\r
300             throw new IllegalStateException("Client is not connected");\r
301         }\r
302         InvokerLocator locator = this.locator;\r
303         disconnect();\r
304         connect(locator);\r
305     }\r
306 \r
307     public AutoConfigurationService getConfigurationService() {\r
308         return cfg;\r
309     }\r
310 \r
311     public synchronized String getServerName() {\r
312         if (locator == null) {\r
313             throw new IllegalStateException("Client is not connected");\r
314         }\r
315         if (serverName == null) {\r
316             if (cfg == null) { // compatibility\r
317                 serverName = RemotingService.ping(locator.getHost(),\r
318                         locator.getPort());\r
319             } else {\r
320                 serverName = cfg.getServerConfiguration().getProductInfo();\r
321             }\r
322         }\r
323         return serverName;\r
324     }\r
325 \r
326     public synchronized boolean isConnected() {\r
327         return true;\r
328     }\r
329 \r
330     public String getServerHost() {\r
331         if (locator == null) {\r
332             throw new IllegalStateException("Client is not connected");\r
333         }\r
334         return locator.getHost();\r
335     }\r
336 \r
337     public int getServerPort() {\r
338         if (locator == null) {\r
339             throw new IllegalStateException("Client is not connected");\r
340         }\r
341         return locator.getPort();\r
342     }\r
343 \r
344     public InvokerLocator getLocator() {\r
345         return locator;\r
346     }\r
347 \r
348     public synchronized LoginHandler getLoginHandler() {\r
349         return loginHandler;\r
350     }\r
351 \r
352     public synchronized void setLoginHandler(LoginHandler loginHandler) {\r
353         this.loginHandler = loginHandler;\r
354     }\r
355 \r
356     public RepositoryManager getRepositoryManager() throws Exception {\r
357         if (repositoryMgr == null) {\r
358             repositoryMgr = Framework.getService(RepositoryManager.class);\r
359         }\r
360         return repositoryMgr;\r
361     }\r
362 \r
363     /**\r
364      * Gets the repositories available on the connected server.\r
365      *\r
366      * @return the repositories\r
367      */\r
368     public Repository[] getRepositories() throws Exception {\r
369         Collection<Repository> repos = getRepositoryManager().getRepositories();\r
370         return repos.toArray(new Repository[repos.size()]);\r
371     }\r
372 \r
373     public Repository getDefaultRepository() throws Exception {\r
374         return getRepositoryManager().getDefaultRepository();\r
375     }\r
376 \r
377     public Repository getRepository(String name) throws Exception {\r
378         return getRepositoryManager().getRepository(name);\r
379     }\r
380 \r
381     /*\r
382      * Open a Nuxeo repo session using the passed in repoDomain and use the default tx timeout period\r
383      */\r
384     public RepositoryInstance openRepository(RepositoryDomainType repoDomain) throws Exception {\r
385         return openRepository(repoDomain.getRepositoryName(), -1);\r
386     }\r
387     \r
388     /*\r
389      * Open a Nuxeo repo session using the passed in repoDomain and use the default tx timeout period\r
390      */\r
391     public RepositoryInstance openRepository(String repoName) throws Exception {\r
392         return openRepository(repoName, -1);\r
393     }    \r
394 \r
395     /*\r
396      * Open a Nuxeo repo session using the default repo with the specified (passed in) tx timeout period\r
397      */\r
398     @Deprecated\r
399     public RepositoryInstance openRepository(int timeoutSeconds) throws Exception {\r
400         return openRepository(null, timeoutSeconds);\r
401     }\r
402 \r
403     /*\r
404      * Open a Nuxeo repo session using the default repo with the default tx timeout period\r
405      */\r
406     @Deprecated\r
407     public RepositoryInstance openRepository() throws Exception {\r
408         return openRepository(null, -1 /*default timeout period*/);\r
409     }\r
410 \r
411     public RepositoryInstance openRepository(String repoName, int timeoutSeconds) throws Exception {\r
412         RepositoryInstance result = null;\r
413         \r
414         if (timeoutSeconds > 0) {\r
415                 TransactionManager transactionMgr = TransactionHelper.lookupTransactionManager();\r
416                 transactionMgr.setTransactionTimeout(timeoutSeconds);\r
417                 if (logger.isInfoEnabled()) {\r
418                         logger.info(String.format("Changing current request's transaction timeout period to %d seconds",\r
419                                         timeoutSeconds));\r
420                 }\r
421         }\r
422         \r
423         //  REM 10/29/2013 - We may want to add this clause if (!TransactionHelper.isTransactionActive()) {\r
424         boolean startTransaction = TransactionHelper.startTransaction();\r
425         if (startTransaction == false) {\r
426                 logger.warn("Could not start a Nuxeo transaction with the TransactionHelper class.");\r
427         }\r
428         \r
429         Repository repository = null;\r
430         if (repoName != null) {\r
431                 repository = getRepositoryManager().getRepository(repoName);\r
432         } else {\r
433                 repository = getRepositoryManager().getDefaultRepository(); // Add a log info statement here stating that since no repo name was given we'll use the default repo instead\r
434         }\r
435         \r
436         if (repository != null) {\r
437                 result = newRepositoryInstance(repository);\r
438                 String key = result.getSessionId();\r
439                 repositoryInstances.put(key, result);\r
440                 if (logger.isTraceEnabled()) {\r
441                         logger.trace("Added a new repository instance to our repo list.  Current count is now: "\r
442                                         + repositoryInstances.size());\r
443                 }\r
444         } else {\r
445                 String errMsg = String.format("Could not open a session to the Nuxeo repository='%s'", repoName);\r
446                 logger.error(errMsg);\r
447                 throw new Exception(errMsg);\r
448         }\r
449 \r
450         return result;\r
451     }\r
452 \r
453     public void releaseRepository(RepositoryInstance repo) throws Exception {\r
454         String key = repo.getSessionId();\r
455 \r
456         try {\r
457                 repo.save();\r
458             repo.close();\r
459         } catch (Exception e) {\r
460                 logger.error("Possible data loss.  Could not save and/or release the repository.", e);\r
461                 throw e;\r
462         } finally {\r
463             RepositoryInstance wasRemoved = repositoryInstances.remove(key);\r
464             if (logger.isTraceEnabled()) {\r
465                 if (wasRemoved != null) {\r
466                         logger.trace("Removed a repository instance from our repo list.  Current count is now: "\r
467                                         + repositoryInstances.size());\r
468                 } else {\r
469                         logger.trace("Could not remove a repository instance from our repo list.  Current count is now: "\r
470                                         + repositoryInstances.size());\r
471                 }\r
472             }\r
473             //if (TransactionHelper.isTransactionActiveOrMarkedRollback())\r
474             TransactionHelper.commitOrRollbackTransaction();\r
475         }\r
476     }\r
477 \r
478 //    public RepositoryInstance[] getRepositoryInstances() {\r
479 //        return repositoryInstances.toArray(new RepositoryInstance[repositoryInstances.size()]);\r
480 //    }\r
481 \r
482     public static RepositoryInstance newRepositoryInstance(Repository repository) {\r
483         ClassLoader cl = Thread.currentThread().getContextClassLoader();\r
484         if (cl == null) {\r
485             cl = NuxeoClientEmbedded.class.getClassLoader();\r
486         }\r
487         return new RepositoryInstanceHandler(repository).getProxy(); // Why a proxy here?\r
488     }\r
489 \r
490     public void addConnectionListener(ConnectionListener listener) {\r
491         connectionListeners.add(listener);\r
492     }\r
493 \r
494     public void removeConnectionListener(ConnectionListener listener) {\r
495         connectionListeners.remove(listener);\r
496     }\r
497 \r
498     private void fireDisconnected(NuxeoClientEmbedded client) {\r
499         Object[] listeners = connectionListeners.getListeners();\r
500         for (Object listener : listeners) {\r
501 //            ((ConnectionListener) listener).disconnected(client);\r
502         }\r
503     }\r
504 \r
505     private void fireConnected(NuxeoClientEmbedded client) {\r
506         Object[] listeners = connectionListeners.getListeners();\r
507         for (Object listener : listeners) {\r
508 //            ((ConnectionListener) listener).connected(client);\r
509         }\r
510     }    \r
511 }\r