1 package org
.argeo
.cms
.internal
.kernel
;
3 import static org
.argeo
.node
.DataModelNamespace
.CMS_DATA_MODEL_NAMESPACE
;
6 import java
.io
.InputStreamReader
;
8 import java
.lang
.management
.ManagementFactory
;
10 import java
.util
.HashSet
;
11 import java
.util
.Hashtable
;
12 import java
.util
.List
;
16 import javax
.jcr
.Repository
;
17 import javax
.jcr
.Session
;
18 import javax
.security
.auth
.callback
.CallbackHandler
;
20 import org
.apache
.commons
.logging
.Log
;
21 import org
.apache
.commons
.logging
.LogFactory
;
22 import org
.apache
.jackrabbit
.commons
.cnd
.CndImporter
;
23 import org
.apache
.jackrabbit
.core
.RepositoryContext
;
24 import org
.apache
.jackrabbit
.core
.RepositoryImpl
;
25 import org
.argeo
.cms
.CmsException
;
26 import org
.argeo
.jcr
.JcrUtils
;
27 import org
.argeo
.node
.DataModelNamespace
;
28 import org
.argeo
.node
.NodeConstants
;
29 import org
.argeo
.node
.NodeDeployment
;
30 import org
.argeo
.node
.NodeState
;
31 import org
.argeo
.node
.security
.CryptoKeyring
;
32 import org
.argeo
.osgi
.useradmin
.UserAdminConf
;
33 import org
.argeo
.util
.LangUtils
;
34 import org
.osgi
.framework
.Bundle
;
35 import org
.osgi
.framework
.BundleContext
;
36 import org
.osgi
.framework
.Constants
;
37 import org
.osgi
.framework
.FrameworkUtil
;
38 import org
.osgi
.framework
.ServiceReference
;
39 import org
.osgi
.framework
.wiring
.BundleCapability
;
40 import org
.osgi
.framework
.wiring
.BundleWire
;
41 import org
.osgi
.framework
.wiring
.BundleWiring
;
42 import org
.osgi
.service
.cm
.Configuration
;
43 import org
.osgi
.service
.cm
.ConfigurationAdmin
;
44 import org
.osgi
.service
.cm
.ManagedService
;
45 import org
.osgi
.service
.useradmin
.UserAdmin
;
46 import org
.osgi
.util
.tracker
.ServiceTracker
;
48 public class CmsDeployment
implements NodeDeployment
{
49 // private final static String LEGACY_JCR_REPOSITORY_ALIAS =
50 // "argeo.jcr.repository.alias";
52 private final Log log
= LogFactory
.getLog(getClass());
53 private final BundleContext bc
= FrameworkUtil
.getBundle(getClass()).getBundleContext();
55 private DataModels dataModels
;
56 private DeployConfig deployConfig
;
57 private HomeRepository homeRepository
;
59 private Long availableSince
;
61 private final boolean cleanState
;
63 private NodeHttp nodeHttp
;
66 private boolean nodeAvailable
= false;
67 private boolean userAdminAvailable
= false;
68 private boolean httpExpected
= false;
69 private boolean httpAvailable
= false;
71 public CmsDeployment() {
72 ServiceReference
<NodeState
> nodeStateSr
= bc
.getServiceReference(NodeState
.class);
73 if (nodeStateSr
== null)
74 throw new CmsException("No node state available");
76 NodeState nodeState
= bc
.getService(nodeStateSr
);
77 cleanState
= nodeState
.isClean();
79 nodeHttp
= new NodeHttp(cleanState
);
80 dataModels
= new DataModels(bc
);
84 private void initTrackers() {
85 ServiceTracker
<?
, ?
> httpSt
= new ServiceTracker
<NodeHttp
, NodeHttp
>(bc
, NodeHttp
.class, null) {
88 public NodeHttp
addingService(ServiceReference
<NodeHttp
> reference
) {
91 return super.addingService(reference
);
95 KernelUtils
.asyncOpen(httpSt
);
97 ServiceTracker
<?
, ?
> repoContextSt
= new RepositoryContextStc();
98 // repoContextSt.open();
99 KernelUtils
.asyncOpen(repoContextSt
);
101 ServiceTracker
<?
, ?
> userAdminSt
= new ServiceTracker
<UserAdmin
, UserAdmin
>(bc
, UserAdmin
.class, null) {
103 public UserAdmin
addingService(ServiceReference
<UserAdmin
> reference
) {
104 userAdminAvailable
= true;
106 return super.addingService(reference
);
109 // userAdminSt.open();
110 KernelUtils
.asyncOpen(userAdminSt
);
112 ServiceTracker
<?
, ?
> confAdminSt
= new ServiceTracker
<ConfigurationAdmin
, ConfigurationAdmin
>(bc
,
113 ConfigurationAdmin
.class, null) {
115 public ConfigurationAdmin
addingService(ServiceReference
<ConfigurationAdmin
> reference
) {
116 ConfigurationAdmin configurationAdmin
= bc
.getService(reference
);
117 deployConfig
= new DeployConfig(configurationAdmin
, dataModels
, cleanState
);
118 httpExpected
= deployConfig
.getProps(KernelConstants
.JETTY_FACTORY_PID
, "default") != null;
120 // Configuration[] configs = configurationAdmin
121 // .listConfigurations("(service.factoryPid=" +
122 // NodeConstants.NODE_REPOS_FACTORY_PID + ")");
123 // for (Configuration config : configs) {
124 // Object cn = config.getProperties().get(NodeConstants.CN);
125 // if (log.isDebugEnabled())
126 // log.debug("Standalone repo cn: " + cn);
128 Configuration
[] configs
= configurationAdmin
129 .listConfigurations("(service.factoryPid=" + NodeConstants
.NODE_USER_ADMIN_PID
+ ")");
131 boolean hasDomain
= false;
132 for (Configuration config
: configs
) {
133 Object realm
= config
.getProperties().get(UserAdminConf
.realm
.name());
135 log
.debug("Found realm: " + realm
);
140 loadIpaJaasConfiguration();
142 } catch (Exception e
) {
143 throw new CmsException("Cannot initialize config", e
);
145 return super.addingService(reference
);
148 // confAdminSt.open();
149 KernelUtils
.asyncOpen(confAdminSt
);
152 private void loadIpaJaasConfiguration() {
153 if (System
.getProperty(KernelConstants
.JAAS_CONFIG_PROP
) == null) {
154 String jaasConfig
= KernelConstants
.JAAS_CONFIG_IPA
;
155 URL url
= getClass().getClassLoader().getResource(jaasConfig
);
156 KernelUtils
.setJaasConfiguration(url
);
157 log
.debug("Set IPA JAAS configuration.");
161 public void shutdown() {
162 if (nodeHttp
!= null)
164 if (deployConfig
!= null)
168 private void checkReadiness() {
169 if (nodeAvailable
&& userAdminAvailable
&& (httpExpected ? httpAvailable
: true)) {
170 String data
= KernelUtils
.getFrameworkProp(KernelUtils
.OSGI_INSTANCE_AREA
);
171 String state
= KernelUtils
.getFrameworkProp(KernelUtils
.OSGI_CONFIGURATION_AREA
);
172 availableSince
= System
.currentTimeMillis();
173 long jvmUptime
= ManagementFactory
.getRuntimeMXBean().getUptime();
174 String jvmUptimeStr
= " in " + (jvmUptime
/ 1000) + "." + (jvmUptime
% 1000) + "s";
175 log
.info("## ARGEO NODE AVAILABLE" + (log
.isDebugEnabled() ? jvmUptimeStr
: "") + " ##");
176 if (log
.isDebugEnabled()) {
177 log
.debug("## state: " + state
);
179 log
.debug("## data: " + data
);
181 long begin
= bc
.getService(bc
.getServiceReference(NodeState
.class)).getAvailableSince();
182 long initDuration
= System
.currentTimeMillis() - begin
;
183 if (log
.isTraceEnabled())
184 log
.trace("Kernel initialization took " + initDuration
+ "ms");
185 tributeToFreeSoftware(initDuration
);
189 final private void tributeToFreeSoftware(long initDuration
) {
190 if (log
.isTraceEnabled()) {
191 long ms
= initDuration
/ 100;
192 log
.trace("Spend " + ms
+ "ms" + " reflecting on the progress brought to mankind" + " by Free Software...");
193 long beginNano
= System
.nanoTime();
196 } catch (InterruptedException e
) {
199 long durationNano
= System
.nanoTime() - beginNano
;
200 final double M
= 1000d
* 1000d
;
201 double sleepAccuracy
= ((double) durationNano
) / (ms
* M
);
202 log
.trace("Sleep accuracy: " + String
.format("%.2f", 100 - (sleepAccuracy
* 100 - 100)) + " %");
206 private void prepareNodeRepository(Repository deployedNodeRepository
) {
207 if (availableSince
!= null) {
208 throw new CmsException("Deployment is already available");
212 prepareDataModel(NodeConstants
.NODE
, KernelUtils
.openAdminSession(deployedNodeRepository
));
215 private void prepareHomeRepository(RepositoryImpl deployedRepository
) {
216 Hashtable
<String
, String
> regProps
= new Hashtable
<String
, String
>();
217 regProps
.put(NodeConstants
.CN
, NodeConstants
.HOME
);
218 // regProps.put(LEGACY_JCR_REPOSITORY_ALIAS, NodeConstants.HOME);
219 homeRepository
= new HomeRepository(deployedRepository
, false);
221 bc
.registerService(Repository
.class, homeRepository
, regProps
);
223 new ServiceTracker
<CallbackHandler
, CallbackHandler
>(bc
, CallbackHandler
.class, null) {
226 public CallbackHandler
addingService(ServiceReference
<CallbackHandler
> reference
) {
227 NodeKeyRing nodeKeyring
= new NodeKeyRing(homeRepository
);
228 CallbackHandler callbackHandler
= bc
.getService(reference
);
229 nodeKeyring
.setDefaultCallbackHandler(callbackHandler
);
230 bc
.registerService(LangUtils
.names(CryptoKeyring
.class, ManagedService
.class), nodeKeyring
,
231 LangUtils
.dico(Constants
.SERVICE_PID
, NodeConstants
.NODE_KEYRING_PID
));
232 return callbackHandler
;
238 /** Session is logged out. */
239 private void prepareDataModel(String cn
, Session adminSession
) {
241 Set
<String
> processed
= new HashSet
<String
>();
242 bundles
: for (Bundle bundle
: bc
.getBundles()) {
243 BundleWiring wiring
= bundle
.adapt(BundleWiring
.class);
246 if (NodeConstants
.NODE
.equals(cn
))// process all data models
247 processWiring(cn
, adminSession
, wiring
, processed
);
249 List
<BundleCapability
> capabilities
= wiring
.getCapabilities(CMS_DATA_MODEL_NAMESPACE
);
250 for (BundleCapability capability
: capabilities
) {
251 String dataModelName
= (String
) capability
.getAttributes().get(DataModelNamespace
.NAME
);
252 if (dataModelName
.equals(cn
))// process only own data model
253 processWiring(cn
, adminSession
, wiring
, processed
);
258 JcrUtils
.logoutQuietly(adminSession
);
262 private void processWiring(String cn
, Session adminSession
, BundleWiring wiring
, Set
<String
> processed
) {
263 // recursively process requirements first
264 List
<BundleWire
> requiredWires
= wiring
.getRequiredWires(CMS_DATA_MODEL_NAMESPACE
);
265 for (BundleWire wire
: requiredWires
) {
266 processWiring(cn
, adminSession
, wire
.getProviderWiring(), processed
);
268 List
<BundleCapability
> capabilities
= wiring
.getCapabilities(CMS_DATA_MODEL_NAMESPACE
);
269 for (BundleCapability capability
: capabilities
) {
270 registerDataModelCapability(cn
, adminSession
, capability
, processed
);
274 private void registerDataModelCapability(String cn
, Session adminSession
, BundleCapability capability
,
275 Set
<String
> processed
) {
276 Map
<String
, Object
> attrs
= capability
.getAttributes();
277 String name
= (String
) attrs
.get(DataModelNamespace
.NAME
);
278 if (processed
.contains(name
)) {
279 if (log
.isTraceEnabled())
280 log
.trace("Data model " + name
+ " has already been processed");
285 String path
= (String
) attrs
.get(DataModelNamespace
.CND
);
287 File dataModel
= bc
.getBundle().getDataFile("dataModels/" + path
);
288 if (!dataModel
.exists()) {
289 URL url
= capability
.getRevision().getBundle().getResource(path
);
291 throw new CmsException("No data model '" + name
+ "' found under path " + path
);
292 try (Reader reader
= new InputStreamReader(url
.openStream())) {
293 CndImporter
.registerNodeTypes(reader
, adminSession
, true);
295 dataModel
.getParentFile().mkdirs();
296 dataModel
.createNewFile();
297 if (log
.isDebugEnabled())
298 log
.debug("Registered CND " + url
);
299 } catch (Exception e
) {
300 throw new CmsException("Cannot import CND " + url
, e
);
305 if (KernelUtils
.asBoolean((String
) attrs
.get(DataModelNamespace
.ABSTRACT
)))
308 boolean isStandalone
= deployConfig
.isStandalone(name
);
309 boolean publishLocalRepo
;
310 if (isStandalone
&& name
.equals(cn
))// includes the node itself
311 publishLocalRepo
= true;
312 else if (!isStandalone
&& cn
.equals(NodeConstants
.NODE
))
313 publishLocalRepo
= true;
315 publishLocalRepo
= false;
317 if (publishLocalRepo
) {
318 Hashtable
<String
, Object
> properties
= new Hashtable
<>();
319 // properties.put(LEGACY_JCR_REPOSITORY_ALIAS, name);
320 properties
.put(NodeConstants
.CN
, name
);
321 if (name
.equals(NodeConstants
.NODE
))
322 properties
.put(Constants
.SERVICE_RANKING
, Integer
.MAX_VALUE
);
323 LocalRepository localRepository
= new LocalRepository(adminSession
.getRepository(), capability
);
324 bc
.registerService(Repository
.class, localRepository
, properties
);
325 if (log
.isDebugEnabled())
326 log
.debug("Published data model " + name
);
331 public Long
getAvailableSince() {
332 return availableSince
;
335 private class RepositoryContextStc
extends ServiceTracker
<RepositoryContext
, RepositoryContext
> {
337 public RepositoryContextStc() {
338 super(bc
, RepositoryContext
.class, null);
342 public RepositoryContext
addingService(ServiceReference
<RepositoryContext
> reference
) {
343 RepositoryContext repoContext
= bc
.getService(reference
);
344 String cn
= (String
) reference
.getProperty(NodeConstants
.CN
);
346 if (cn
.equals(NodeConstants
.NODE
)) {
347 prepareNodeRepository(repoContext
.getRepository());
348 // TODO separate home repository
349 prepareHomeRepository(repoContext
.getRepository());
350 nodeAvailable
= true;
353 prepareDataModel(cn
, KernelUtils
.openAdminSession(repoContext
.getRepository()));
360 public void modifiedService(ServiceReference
<RepositoryContext
> reference
, RepositoryContext service
) {
364 public void removedService(ServiceReference
<RepositoryContext
> reference
, RepositoryContext service
) {