1 package org
.argeo
.cms
.internal
.kernel
;
3 import java
.lang
.management
.ManagementFactory
;
4 import java
.security
.PrivilegedAction
;
5 import java
.util
.HashMap
;
7 import java
.util
.Properties
;
9 import javax
.jcr
.Repository
;
10 import javax
.jcr
.RepositoryFactory
;
11 import javax
.security
.auth
.Subject
;
12 import javax
.transaction
.TransactionManager
;
13 import javax
.transaction
.TransactionSynchronizationRegistry
;
14 import javax
.transaction
.UserTransaction
;
16 import org
.apache
.commons
.logging
.Log
;
17 import org
.apache
.commons
.logging
.LogFactory
;
18 import org
.apache
.jackrabbit
.util
.TransientFileFactory
;
19 import org
.argeo
.ArgeoException
;
20 import org
.argeo
.cms
.CmsException
;
21 import org
.argeo
.cms
.internal
.transaction
.SimpleTransactionManager
;
22 import org
.argeo
.jackrabbit
.OsgiJackrabbitRepositoryFactory
;
23 import org
.argeo
.jcr
.ArgeoJcrConstants
;
24 import org
.eclipse
.equinox
.http
.servlet
.ExtendedHttpService
;
25 import org
.osgi
.framework
.BundleContext
;
26 import org
.osgi
.framework
.ServiceEvent
;
27 import org
.osgi
.framework
.ServiceListener
;
28 import org
.osgi
.framework
.ServiceReference
;
29 import org
.osgi
.service
.http
.HttpService
;
30 import org
.osgi
.util
.tracker
.ServiceTracker
;
33 * Argeo CMS Kernel. Responsible for :
36 * <li>provisioning</li>
37 * <li>transaction</li>
39 * <li>local and remote file systems access</li>
43 final class Kernel
implements ServiceListener
{
44 private final static Log log
= LogFactory
.getLog(Kernel
.class);
46 private final BundleContext bundleContext
= Activator
.getBundleContext();
47 private final NodeSecurity nodeSecurity
;
49 ThreadGroup threadGroup
= new ThreadGroup(Kernel
.class.getSimpleName());
52 private SimpleTransactionManager transactionManager
;
53 private OsgiJackrabbitRepositoryFactory repositoryFactory
;
54 private NodeHttp nodeHttp
;
55 private KernelThread kernelThread
;
58 nodeSecurity
= new NodeSecurity(bundleContext
);
62 Subject
.doAs(nodeSecurity
.getKernelSubject(),
63 new PrivilegedAction
<Void
>() {
74 private void doInit() {
75 ClassLoader currentContextCl
= Thread
.currentThread()
76 .getContextClassLoader();
77 Thread
.currentThread().setContextClassLoader(
78 Kernel
.class.getClassLoader());
79 long begin
= System
.currentTimeMillis();
83 transactionManager
= new SimpleTransactionManager();
86 node
= new JackrabbitNode(bundleContext
);
88 // JCR repository factory
89 repositoryFactory
= new OsgiJackrabbitRepositoryFactory();
92 nodeSecurity
.getUserAdmin().setTransactionManager(
96 // ExtendedHttpService httpService = waitForHttpService();
97 // nodeHttp = new NodeHttp(httpService, node);
98 ServiceReference
<ExtendedHttpService
> sr
= bundleContext
99 .getServiceReference(ExtendedHttpService
.class);
104 kernelThread
= new KernelThread(this);
105 kernelThread
.setContextClassLoader(Kernel
.class.getClassLoader());
106 kernelThread
.start();
108 // Publish services to OSGi
109 bundleContext
.registerService(TransactionManager
.class,
110 transactionManager
, null);
111 bundleContext
.registerService(UserTransaction
.class,
112 transactionManager
, null);
113 bundleContext
.registerService(
114 TransactionSynchronizationRegistry
.class,
115 transactionManager
.getTransactionSynchronizationRegistry(),
117 nodeSecurity
.publish();
118 node
.publish(repositoryFactory
);
119 bundleContext
.registerService(RepositoryFactory
.class,
120 repositoryFactory
, null);
122 bundleContext
.addServiceListener(Kernel
.this);
123 } catch (Exception e
) {
124 log
.error("Cannot initialize Argeo CMS", e
);
125 throw new ArgeoException("Cannot initialize", e
);
127 Thread
.currentThread().setContextClassLoader(currentContextCl
);
130 long jvmUptime
= ManagementFactory
.getRuntimeMXBean().getUptime();
131 log
.info("## ARGEO CMS UP in " + (jvmUptime
/ 1000) + "."
132 + (jvmUptime
% 1000) + "s ##");
133 long initDuration
= System
.currentTimeMillis() - begin
;
134 if (log
.isTraceEnabled())
135 log
.trace("Kernel initialization took " + initDuration
+ "ms");
136 directorsCut(initDuration
);
140 long begin
= System
.currentTimeMillis();
142 kernelThread
.destroyAndJoin();
144 if (nodeHttp
!= null)
146 // if (nodeSecurity != null)
147 // nodeSecurity.destroy();
151 bundleContext
.removeServiceListener(this);
153 // Clean hanging threads from Jackrabbit
154 TransientFileFactory
.shutdown();
156 // Clean hanging Gogo shell thread
157 new GogoShellKiller().start();
159 nodeSecurity
.destroy();
160 long duration
= System
.currentTimeMillis() - begin
;
161 log
.info("## ARGEO CMS DOWN in " + (duration
/ 1000) + "."
162 + (duration
% 1000) + "s ##");
166 public void serviceChanged(ServiceEvent event
) {
167 ServiceReference
<?
> sr
= event
.getServiceReference();
168 Object service
= bundleContext
.getService(sr
);
169 if (service
instanceof Repository
) {
170 Object jcrRepoAlias
= sr
171 .getProperty(ArgeoJcrConstants
.JCR_REPOSITORY_ALIAS
);
172 if (jcrRepoAlias
!= null) {// JCR repository
173 String alias
= jcrRepoAlias
.toString();
174 Repository repository
= (Repository
) bundleContext
176 Map
<String
, Object
> props
= new HashMap
<String
, Object
>();
177 for (String key
: sr
.getPropertyKeys())
178 props
.put(key
, sr
.getProperty(key
));
179 if (ServiceEvent
.REGISTERED
== event
.getType()) {
181 repositoryFactory
.register(repository
, props
);
182 nodeHttp
.registerRepositoryServlets(alias
, repository
);
183 } catch (Exception e
) {
184 throw new CmsException(
185 "Could not publish JCR repository " + alias
, e
);
187 } else if (ServiceEvent
.UNREGISTERING
== event
.getType()) {
188 repositoryFactory
.unregister(repository
, props
);
189 nodeHttp
.unregisterRepositoryServlets(alias
);
192 } else if (service
instanceof ExtendedHttpService
) {
193 if (ServiceEvent
.REGISTERED
== event
.getType()) {
195 } else if (ServiceEvent
.UNREGISTERING
== event
.getType()) {
202 private void addHttpService(ServiceReference
<?
> sr
) {
203 // for (String key : sr.getPropertyKeys())
204 // log.debug(key + "=" + sr.getProperty(key));
205 ExtendedHttpService httpService
= (ExtendedHttpService
) bundleContext
207 // TODO find constants
208 Object httpPort
= sr
.getProperty("http.port");
209 Object httpsPort
= sr
.getProperty("https.port");
210 nodeHttp
= new NodeHttp(httpService
, node
);
211 if (log
.isDebugEnabled())
212 log
.debug("HTTP " + httpPort
213 + (httpsPort
!= null ?
" - HTTPS " + httpsPort
: ""));
216 private ExtendedHttpService
waitForHttpService() {
217 final ServiceTracker
<ExtendedHttpService
, ExtendedHttpService
> st
= new ServiceTracker
<ExtendedHttpService
, ExtendedHttpService
>(
218 bundleContext
, ExtendedHttpService
.class, null);
220 ExtendedHttpService httpService
;
222 httpService
= st
.waitForService(1000);
223 } catch (InterruptedException e
) {
227 if (httpService
== null)
228 throw new CmsException("Could not find "
229 + ExtendedHttpService
.class + " service.");
233 final private static void directorsCut(long initDuration
) {
234 // final long ms = 128l + (long) (Math.random() * 128d);
235 long ms
= initDuration
/ 100;
236 log
.info("Spend " + ms
+ "ms"
237 + " reflecting on the progress brought to mankind"
238 + " by Free Software...");
239 long beginNano
= System
.nanoTime();
242 } catch (InterruptedException e
) {
245 long durationNano
= System
.nanoTime() - beginNano
;
246 final double M
= 1000d
* 1000d
;
247 double sleepAccuracy
= ((double) durationNano
) / (ms
* M
);
248 if (log
.isDebugEnabled())
249 log
.debug("Sleep accuracy: "
250 + String
.format("%.2f", 100 - (sleepAccuracy
* 100 - 100))
254 /** Workaround for blocking Gogo shell by system shutdown. */
255 private class GogoShellKiller
extends Thread
{
257 public GogoShellKiller() {
258 super("Gogo shell killer");
264 ThreadGroup rootTg
= getRootThreadGroup(null);
265 Thread gogoShellThread
= findGogoShellThread(rootTg
);
266 if (gogoShellThread
== null)
268 while (getNonDaemonCount(rootTg
) > 2) {
271 } catch (InterruptedException e
) {
275 gogoShellThread
= findGogoShellThread(rootTg
);
276 if (gogoShellThread
== null)
282 private static ThreadGroup
getRootThreadGroup(ThreadGroup tg
) {
284 tg
= Thread
.currentThread().getThreadGroup();
285 if (tg
.getParent() == null)
288 return getRootThreadGroup(tg
.getParent());
291 private static int getNonDaemonCount(ThreadGroup rootThreadGroup
) {
292 Thread
[] threads
= new Thread
[rootThreadGroup
.activeCount()];
293 rootThreadGroup
.enumerate(threads
);
294 int nonDameonCount
= 0;
295 for (Thread t
: threads
)
298 return nonDameonCount
;
301 private static Thread
findGogoShellThread(ThreadGroup rootThreadGroup
) {
302 Thread
[] threads
= new Thread
[rootThreadGroup
.activeCount()];
303 rootThreadGroup
.enumerate(threads
, true);
304 for (Thread thread
: threads
) {
305 if (thread
.getName().equals("Gogo shell"))