1 package org
.argeo
.cms
.internal
.kernel
;
3 import static org
.argeo
.node
.DataModelNamespace
.CMS_DATA_MODEL_NAMESPACE
;
5 import java
.io
.InputStreamReader
;
7 import java
.lang
.management
.ManagementFactory
;
9 import java
.util
.HashSet
;
10 import java
.util
.Hashtable
;
11 import java
.util
.List
;
15 import javax
.jcr
.Repository
;
16 import javax
.jcr
.Session
;
18 import org
.apache
.commons
.logging
.Log
;
19 import org
.apache
.commons
.logging
.LogFactory
;
20 import org
.apache
.jackrabbit
.commons
.cnd
.CndImporter
;
21 import org
.apache
.jackrabbit
.core
.RepositoryContext
;
22 import org
.argeo
.cms
.CmsException
;
23 import org
.argeo
.jcr
.ArgeoJcrConstants
;
24 import org
.argeo
.jcr
.JcrUtils
;
25 import org
.argeo
.node
.DataModelNamespace
;
26 import org
.argeo
.node
.NodeConstants
;
27 import org
.argeo
.node
.NodeDeployment
;
28 import org
.argeo
.node
.NodeState
;
29 import org
.osgi
.framework
.Bundle
;
30 import org
.osgi
.framework
.BundleContext
;
31 import org
.osgi
.framework
.FrameworkUtil
;
32 import org
.osgi
.framework
.ServiceReference
;
33 import org
.osgi
.framework
.wiring
.BundleCapability
;
34 import org
.osgi
.framework
.wiring
.BundleWire
;
35 import org
.osgi
.framework
.wiring
.BundleWiring
;
36 import org
.osgi
.service
.http
.HttpService
;
37 import org
.osgi
.service
.useradmin
.UserAdmin
;
38 import org
.osgi
.util
.tracker
.ServiceTracker
;
40 public class CmsDeployment
implements NodeDeployment
{
41 private final Log log
= LogFactory
.getLog(getClass());
42 private final BundleContext bc
= FrameworkUtil
.getBundle(getClass()).getBundleContext();
44 private final DeployConfig deployConfig
;
45 private HomeRepository homeRepository
;
47 private Long availableSince
;
50 private boolean nodeAvailable
= false;
51 private boolean userAdminAvailable
= false;
52 private boolean httpExpected
= false;
53 private boolean httpAvailable
= false;
55 public CmsDeployment() {
56 ServiceReference
<NodeState
> nodeStateSr
= bc
.getServiceReference(NodeState
.class);
57 if (nodeStateSr
== null)
58 throw new CmsException("No node state available");
60 NodeState nodeState
= bc
.getService(nodeStateSr
);
61 deployConfig
= new DeployConfig(nodeState
.isClean());
62 httpExpected
= deployConfig
.getProps(KernelConstants
.JETTY_FACTORY_PID
, "default") != null;
67 private void initTrackers() {
68 new PrepareHttpStc().open();
69 new RepositoryContextStc().open();
70 new ServiceTracker
<UserAdmin
, UserAdmin
>(bc
, UserAdmin
.class, null) {
72 public UserAdmin
addingService(ServiceReference
<UserAdmin
> reference
) {
73 userAdminAvailable
= true;
75 return super.addingService(reference
);
80 public void shutdown() {
84 private void checkReadiness() {
85 if (nodeAvailable
&& userAdminAvailable
&& (httpExpected ? httpAvailable
: true)) {
86 availableSince
= System
.currentTimeMillis();
87 long jvmUptime
= ManagementFactory
.getRuntimeMXBean().getUptime();
88 log
.info("## ARGEO CMS AVAILABLE in " + (jvmUptime
/ 1000) + "." + (jvmUptime
% 1000) + "s ##");
89 long begin
= bc
.getService(bc
.getServiceReference(NodeState
.class)).getAvailableSince();
90 long initDuration
= System
.currentTimeMillis() - begin
;
91 if (log
.isTraceEnabled())
92 log
.trace("Kernel initialization took " + initDuration
+ "ms");
93 directorsCut(initDuration
);
97 final private void directorsCut(long initDuration
) {
98 // final long ms = 128l + (long) (Math.random() * 128d);
99 long ms
= initDuration
/ 100;
100 log
.info("Spend " + ms
+ "ms" + " reflecting on the progress brought to mankind" + " by Free Software...");
101 long beginNano
= System
.nanoTime();
104 } catch (InterruptedException e
) {
107 long durationNano
= System
.nanoTime() - beginNano
;
108 final double M
= 1000d
* 1000d
;
109 double sleepAccuracy
= ((double) durationNano
) / (ms
* M
);
110 if (log
.isDebugEnabled())
111 log
.debug("Sleep accuracy: " + String
.format("%.2f", 100 - (sleepAccuracy
* 100 - 100)) + " %");
114 private void prepareNodeRepository(Repository deployedNodeRepository
) {
115 if (availableSince
!= null) {
116 throw new CmsException("Deployment is already available");
119 prepareDataModel(KernelUtils
.openAdminSession(deployedNodeRepository
));
120 Hashtable
<String
, String
> regProps
= new Hashtable
<String
, String
>();
121 regProps
.put(NodeConstants
.CN
, ArgeoJcrConstants
.ALIAS_HOME
);
122 regProps
.put(ArgeoJcrConstants
.JCR_REPOSITORY_ALIAS
, ArgeoJcrConstants
.ALIAS_HOME
);
123 homeRepository
= new HomeRepository(deployedNodeRepository
);
125 bc
.registerService(Repository
.class, homeRepository
, regProps
);
128 /** Session is logged out. */
129 private void prepareDataModel(Session adminSession
) {
131 Set
<String
> processed
= new HashSet
<String
>();
132 bundles
: for (Bundle bundle
: bc
.getBundles()) {
133 BundleWiring wiring
= bundle
.adapt(BundleWiring
.class);
134 if (wiring
== null) {
135 if (log
.isTraceEnabled())
136 log
.error("No wiring for " + bundle
.getSymbolicName());
139 processWiring(adminSession
, wiring
, processed
);
142 JcrUtils
.logoutQuietly(adminSession
);
146 private void processWiring(Session adminSession
, BundleWiring wiring
, Set
<String
> processed
) {
147 // recursively process requirements first
148 List
<BundleWire
> requiredWires
= wiring
.getRequiredWires(CMS_DATA_MODEL_NAMESPACE
);
149 for (BundleWire wire
: requiredWires
) {
150 processWiring(adminSession
, wire
.getProviderWiring(), processed
);
151 // registerCnd(adminSession, wire.getCapability(), processed);
153 List
<BundleCapability
> capabilities
= wiring
.getCapabilities(CMS_DATA_MODEL_NAMESPACE
);
154 for (BundleCapability capability
: capabilities
) {
155 registerCnd(adminSession
, capability
, processed
);
159 private void registerCnd(Session adminSession
, BundleCapability capability
, Set
<String
> processed
) {
160 Map
<String
, Object
> attrs
= capability
.getAttributes();
161 String name
= attrs
.get(DataModelNamespace
.CAPABILITY_NAME_ATTRIBUTE
).toString();
162 if (processed
.contains(name
)) {
163 if (log
.isTraceEnabled())
164 log
.trace("Data model " + name
+ " has already been processed");
167 String path
= attrs
.get(DataModelNamespace
.CAPABILITY_CND_ATTRIBUTE
).toString();
168 URL url
= capability
.getRevision().getBundle().getResource(path
);
169 try (Reader reader
= new InputStreamReader(url
.openStream())) {
170 CndImporter
.registerNodeTypes(reader
, adminSession
, true);
172 if (log
.isDebugEnabled())
173 log
.debug("Registered CND " + url
);
174 } catch (Exception e
) {
175 throw new CmsException("Cannot import CND " + url
, e
);
178 Hashtable
<String
, Object
> properties
= new Hashtable
<>();
179 properties
.put(ArgeoJcrConstants
.JCR_REPOSITORY_ALIAS
, name
);
180 properties
.put(NodeConstants
.CN
, name
);
181 bc
.registerService(Repository
.class, adminSession
.getRepository(), properties
);
182 if (log
.isDebugEnabled())
183 log
.debug("Published data model " + name
);
187 public Long
getAvailableSince() {
188 return availableSince
;
191 private class RepositoryContextStc
extends ServiceTracker
<RepositoryContext
, RepositoryContext
> {
193 public RepositoryContextStc() {
194 super(bc
, RepositoryContext
.class, null);
198 public RepositoryContext
addingService(ServiceReference
<RepositoryContext
> reference
) {
199 RepositoryContext nodeRepo
= bc
.getService(reference
);
200 Object cn
= reference
.getProperty(NodeConstants
.CN
);
201 if (cn
!= null && cn
.equals(ArgeoJcrConstants
.ALIAS_NODE
)) {
202 prepareNodeRepository(nodeRepo
.getRepository());
203 nodeAvailable
= true;
210 public void modifiedService(ServiceReference
<RepositoryContext
> reference
, RepositoryContext service
) {
214 public void removedService(ServiceReference
<RepositoryContext
> reference
, RepositoryContext service
) {
219 private class PrepareHttpStc
extends ServiceTracker
<HttpService
, HttpService
> {
220 private DataHttp dataHttp
;
221 private NodeHttp nodeHttp
;
223 public PrepareHttpStc() {
224 super(bc
, HttpService
.class, null);
228 public HttpService
addingService(ServiceReference
<HttpService
> reference
) {
229 HttpService httpService
= addHttpService(reference
);
234 public void removedService(ServiceReference
<HttpService
> reference
, HttpService service
) {
235 if (dataHttp
!= null)
238 if (nodeHttp
!= null)
243 private HttpService
addHttpService(ServiceReference
<HttpService
> sr
) {
244 HttpService httpService
= bc
.getService(sr
);
245 // TODO find constants
246 Object httpPort
= sr
.getProperty("http.port");
247 Object httpsPort
= sr
.getProperty("https.port");
248 dataHttp
= new DataHttp(httpService
);
249 nodeHttp
= new NodeHttp(httpService
, bc
);
250 log
.info(httpPortsMsg(httpPort
, httpsPort
));
251 httpAvailable
= true;
256 private String
httpPortsMsg(Object httpPort
, Object httpsPort
) {
257 return "HTTP " + httpPort
+ (httpsPort
!= null ?
" - HTTPS " + httpsPort
: "");