]> git.argeo.org Git - lgpl/argeo-commons.git/blob - kernel/Kernel.java
Prepare next development cycle
[lgpl/argeo-commons.git] / kernel / Kernel.java
1 package org.argeo.cms.internal.kernel;
2
3 import java.lang.management.ManagementFactory;
4 import java.net.URL;
5 import java.security.PrivilegedAction;
6 import java.util.HashMap;
7 import java.util.Map;
8
9 import javax.jcr.Repository;
10 import javax.jcr.RepositoryFactory;
11 import javax.security.auth.Subject;
12 import javax.security.auth.login.LoginContext;
13 import javax.security.auth.login.LoginException;
14
15 import org.apache.commons.logging.Log;
16 import org.apache.commons.logging.LogFactory;
17 import org.apache.jackrabbit.util.TransientFileFactory;
18 import org.argeo.ArgeoException;
19 import org.argeo.cms.CmsException;
20 import org.argeo.cms.KernelHeader;
21 import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory;
22 import org.argeo.jcr.ArgeoJcrConstants;
23 import org.argeo.security.core.InternalAuthentication;
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.util.tracker.ServiceTracker;
30 import org.springframework.security.core.context.SecurityContextHolder;
31
32 /**
33 * Argeo CMS Kernel. Responsible for :
34 * <ul>
35 * <li>security</li>
36 * <li>provisioning</li>
37 * <li>transaction</li>
38 * <li>logging</li>
39 * <li>local and remote file systems access</li>
40 * <li>OS access</li>
41 * </ul>
42 */
43 final class Kernel implements ServiceListener {
44 private final static Log log = LogFactory.getLog(Kernel.class);
45
46 private final BundleContext bundleContext = Activator.getBundleContext();
47
48 ThreadGroup threadGroup = new ThreadGroup(Kernel.class.getSimpleName());
49 JackrabbitNode node;
50 OsgiJackrabbitRepositoryFactory repositoryFactory;
51 NodeSecurity nodeSecurity;
52 NodeHttp nodeHttp;
53 private KernelThread kernelThread;
54
55 private final Subject kernelSubject = new Subject();
56
57 public Kernel() {
58 URL url = getClass().getClassLoader().getResource(
59 KernelConstants.JAAS_CONFIG);
60 System.setProperty("java.security.auth.login.config",
61 url.toExternalForm());
62 try {
63 LoginContext kernelLc = new LoginContext(
64 KernelHeader.LOGIN_CONTEXT_SYSTEM, kernelSubject);
65 kernelLc.login();
66 } catch (LoginException e) {
67 throw new CmsException("Cannot log in kernel", e);
68 }
69 }
70
71 final void init() {
72 Subject.doAs(kernelSubject, new PrivilegedAction<Void>() {
73
74 @Override
75 public Void run() {
76 doInit();
77 return null;
78 }
79
80 });
81 }
82
83 private void doInit() {
84 ClassLoader currentContextCl = Thread.currentThread()
85 .getContextClassLoader();
86 Thread.currentThread().setContextClassLoader(
87 Kernel.class.getClassLoader());
88 long begin = System.currentTimeMillis();
89 InternalAuthentication initAuth = new InternalAuthentication(
90 KernelConstants.DEFAULT_SECURITY_KEY);
91 SecurityContextHolder.getContext().setAuthentication(initAuth);
92
93 try {
94 // Jackrabbit node
95 node = new JackrabbitNode(bundleContext);
96
97 // JCR repository factory
98 repositoryFactory = new OsgiJackrabbitRepositoryFactory();
99
100 // Authentication
101 nodeSecurity = new NodeSecurity(bundleContext, node);
102
103 // Equinox dependency
104 ExtendedHttpService httpService = waitForHttpService();
105 nodeHttp = new NodeHttp(httpService, node, nodeSecurity);
106
107 // Kernel thread
108 kernelThread = new KernelThread(this);
109 kernelThread.setContextClassLoader(Kernel.class.getClassLoader());
110 kernelThread.start();
111
112 // Publish services to OSGi
113 nodeSecurity.publish();
114 node.publish(repositoryFactory);
115 bundleContext.registerService(RepositoryFactory.class,
116 repositoryFactory, null);
117
118 bundleContext.addServiceListener(Kernel.this);
119 } catch (Exception e) {
120 log.error("Cannot initialize Argeo CMS", e);
121 throw new ArgeoException("Cannot initialize", e);
122 } finally {
123 Thread.currentThread().setContextClassLoader(currentContextCl);
124 }
125
126 long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
127 log.info("## ARGEO CMS UP in " + (jvmUptime / 1000) + "."
128 + (jvmUptime % 1000) + "s ##");
129 long initDuration = System.currentTimeMillis() - begin;
130 if (log.isTraceEnabled())
131 log.trace("Kernel initialization took " + initDuration + "ms");
132 directorsCut(initDuration);
133 }
134
135 void destroy() {
136 long begin = System.currentTimeMillis();
137
138 kernelThread.destroyAndJoin();
139
140 if (nodeHttp != null)
141 nodeHttp.destroy();
142 if (nodeSecurity != null)
143 nodeSecurity.destroy();
144 if (node != null)
145 node.destroy();
146
147 bundleContext.removeServiceListener(this);
148
149 // Clean hanging threads from Jackrabbit
150 TransientFileFactory.shutdown();
151
152 try {
153 LoginContext kernelLc = new LoginContext(
154 KernelHeader.LOGIN_CONTEXT_SYSTEM, kernelSubject);
155 kernelLc.logout();
156 } catch (LoginException e) {
157 throw new CmsException("Cannot log in kernel", e);
158 }
159
160 long duration = System.currentTimeMillis() - begin;
161 log.info("## ARGEO CMS DOWN in " + (duration / 1000) + "."
162 + (duration % 1000) + "s ##");
163 }
164
165 @Override
166 public void serviceChanged(ServiceEvent event) {
167 ServiceReference<?> sr = event.getServiceReference();
168 Object jcrRepoAlias = sr
169 .getProperty(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS);
170 if (jcrRepoAlias != null) {// JCR repository
171 String alias = jcrRepoAlias.toString();
172 Repository repository = (Repository) bundleContext.getService(sr);
173 Map<String, Object> props = new HashMap<String, Object>();
174 for (String key : sr.getPropertyKeys())
175 props.put(key, sr.getProperty(key));
176 if (ServiceEvent.REGISTERED == event.getType()) {
177 try {
178 repositoryFactory.register(repository, props);
179 nodeHttp.registerRepositoryServlets(alias, repository);
180 } catch (Exception e) {
181 throw new CmsException("Could not publish JCR repository "
182 + alias, e);
183 }
184 } else if (ServiceEvent.UNREGISTERING == event.getType()) {
185 repositoryFactory.unregister(repository, props);
186 nodeHttp.unregisterRepositoryServlets(alias);
187 }
188 }
189
190 }
191
192 private ExtendedHttpService waitForHttpService() {
193 final ServiceTracker<ExtendedHttpService, ExtendedHttpService> st = new ServiceTracker<ExtendedHttpService, ExtendedHttpService>(
194 bundleContext, ExtendedHttpService.class, null);
195 st.open();
196 ExtendedHttpService httpService;
197 try {
198 httpService = st.waitForService(1000);
199 } catch (InterruptedException e) {
200 httpService = null;
201 }
202
203 if (httpService == null)
204 throw new CmsException("Could not find "
205 + ExtendedHttpService.class + " service.");
206 return httpService;
207 }
208
209 final private static void directorsCut(long initDuration) {
210 // final long ms = 128l + (long) (Math.random() * 128d);
211 long ms = initDuration / 100;
212 log.info("Spend " + ms + "ms"
213 + " reflecting on the progress brought to mankind"
214 + " by Free Software...");
215 long beginNano = System.nanoTime();
216 try {
217 Thread.sleep(ms, 0);
218 } catch (InterruptedException e) {
219 // silent
220 }
221 long durationNano = System.nanoTime() - beginNano;
222 final double M = 1000d * 1000d;
223 double sleepAccuracy = ((double) durationNano) / (ms * M);
224 if (log.isDebugEnabled())
225 log.debug("Sleep accuracy: "
226 + String.format("%.2f", 100 - (sleepAccuracy * 100 - 100))
227 + " %");
228 }
229 }