1 package org
.argeo
.cms
.jcr
.internal
;
3 import static org
.argeo
.cms
.osgi
.DataModelNamespace
.CMS_DATA_MODEL_NAMESPACE
;
5 import java
.util
.ArrayList
;
6 import java
.util
.Collections
;
9 import java
.util
.TreeMap
;
11 import org
.apache
.commons
.logging
.Log
;
12 import org
.apache
.commons
.logging
.LogFactory
;
13 import org
.argeo
.cms
.CmsException
;
14 import org
.argeo
.cms
.osgi
.DataModelNamespace
;
15 import org
.osgi
.framework
.Bundle
;
16 import org
.osgi
.framework
.BundleContext
;
17 import org
.osgi
.framework
.BundleEvent
;
18 import org
.osgi
.framework
.BundleListener
;
19 import org
.osgi
.framework
.wiring
.BundleCapability
;
20 import org
.osgi
.framework
.wiring
.BundleWire
;
21 import org
.osgi
.framework
.wiring
.BundleWiring
;
23 class DataModels
implements BundleListener
{
24 private final static Log log
= LogFactory
.getLog(DataModels
.class);
26 private Map
<String
, DataModel
> dataModels
= new TreeMap
<>();
28 public DataModels(BundleContext bc
) {
29 for (Bundle bundle
: bc
.getBundles())
30 processBundle(bundle
, null);
31 bc
.addBundleListener(this);
34 public List
<DataModel
> getNonAbstractDataModels() {
35 List
<DataModel
> res
= new ArrayList
<>();
36 for (String name
: dataModels
.keySet()) {
37 DataModel dataModel
= dataModels
.get(name
);
38 if (!dataModel
.isAbstract())
46 public void bundleChanged(BundleEvent event
) {
47 if (event
.getType() == Bundle
.RESOLVED
) {
48 processBundle(event
.getBundle(), null);
49 } else if (event
.getType() == Bundle
.UNINSTALLED
) {
50 BundleWiring wiring
= event
.getBundle().adapt(BundleWiring
.class);
51 List
<BundleCapability
> providedDataModels
= wiring
.getCapabilities(CMS_DATA_MODEL_NAMESPACE
);
52 if (providedDataModels
.size() == 0)
54 for (BundleCapability bundleCapability
: providedDataModels
) {
55 dataModels
.remove(bundleCapability
.getAttributes().get(DataModelNamespace
.NAME
));
61 protected void processBundle(Bundle bundle
, List
<Bundle
> scannedBundles
) {
62 if (scannedBundles
!= null && scannedBundles
.contains(bundle
))
63 throw new IllegalStateException("Cycle in CMS data model requirements for " + bundle
);
64 BundleWiring wiring
= bundle
.adapt(BundleWiring
.class);
66 int bundleState
= bundle
.getState();
67 if (bundleState
!= Bundle
.INSTALLED
&& bundleState
!= Bundle
.UNINSTALLED
) {// ignore unresolved bundles
68 log
.warn("Bundle " + bundle
.getSymbolicName() + " #" + bundle
.getBundleId() + " ("
69 + bundle
.getLocation() + ") cannot be adapted to a wiring");
71 if (log
.isTraceEnabled())
72 log
.warn("Bundle " + bundle
.getSymbolicName() + " is not resolved.");
76 List
<BundleCapability
> providedDataModels
= wiring
.getCapabilities(CMS_DATA_MODEL_NAMESPACE
);
77 if (providedDataModels
.size() == 0)
79 List
<BundleWire
> requiredDataModels
= wiring
.getRequiredWires(CMS_DATA_MODEL_NAMESPACE
);
80 // process requirements first
81 for (BundleWire bundleWire
: requiredDataModels
) {
82 List
<Bundle
> nextScannedBundles
= new ArrayList
<>();
83 if (scannedBundles
!= null)
84 nextScannedBundles
.addAll(scannedBundles
);
85 nextScannedBundles
.add(bundle
);
86 Bundle providerBundle
= bundleWire
.getProvider().getBundle();
87 processBundle(providerBundle
, nextScannedBundles
);
89 for (BundleCapability bundleCapability
: providedDataModels
) {
90 String name
= (String
) bundleCapability
.getAttributes().get(DataModelNamespace
.NAME
);
92 if (!dataModels
.containsKey(name
)) {
93 DataModel dataModel
= new DataModel(name
, bundleCapability
, requiredDataModels
);
94 dataModels
.put(dataModel
.getName(), dataModel
);
99 /** Return a negative depth if dataModel is required by ref, 0 otherwise. */
100 static int required(DataModel ref
, DataModel dataModel
, int depth
) {
101 for (DataModel dm
: ref
.getRequired()) {
102 if (dm
.equals(dataModel
))// found here
104 int d
= required(dm
, dataModel
, depth
- 1);
105 if (d
!= 0)// found deeper
108 return 0;// not found
112 private final String name
;
113 private final boolean abstrct
;
114 // private final boolean standalone;
115 private final String cnd
;
116 private final List
<DataModel
> required
;
118 private DataModel(String name
, BundleCapability bundleCapability
, List
<BundleWire
> requiredDataModels
) {
119 assert CMS_DATA_MODEL_NAMESPACE
.equals(bundleCapability
.getNamespace());
121 Map
<String
, Object
> attrs
= bundleCapability
.getAttributes();
122 abstrct
= KernelUtils
.asBoolean((String
) attrs
.get(DataModelNamespace
.ABSTRACT
));
123 // standalone = KernelUtils.asBoolean((String)
124 // attrs.get(DataModelNamespace.CAPABILITY_STANDALONE_ATTRIBUTE));
125 cnd
= (String
) attrs
.get(DataModelNamespace
.CND
);
126 List
<DataModel
> req
= new ArrayList
<>();
127 for (BundleWire wire
: requiredDataModels
) {
128 String requiredDataModelName
= (String
) wire
.getCapability().getAttributes()
129 .get(DataModelNamespace
.NAME
);
130 assert requiredDataModelName
!= null;
131 DataModel requiredDataModel
= dataModels
.get(requiredDataModelName
);
132 if (requiredDataModel
== null)
133 throw new CmsException("No required data model " + requiredDataModelName
);
134 req
.add(requiredDataModel
);
136 required
= Collections
.unmodifiableList(req
);
139 public String
getName() {
143 public boolean isAbstract() {
147 // public boolean isStandalone() {
148 // return !isAbstract();
151 public String
getCnd() {
155 public List
<DataModel
> getRequired() {
160 // public int compareTo(DataModel o) {
163 // int res = required(this, o, 0);
166 // // the other way round
167 // res = required(o, this, 0);
174 public int hashCode() {
175 return name
.hashCode();
179 public boolean equals(Object obj
) {
180 if (obj
instanceof DataModel
)
181 return ((DataModel
) obj
).name
.equals(name
);
186 public String
toString() {
187 return "Data model " + name
;