]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/kernel/DataModels.java
Prepare release.
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / kernel / DataModels.java
1 package org.argeo.cms.internal.kernel;
2
3 import static org.argeo.node.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
4
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.TreeMap;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.argeo.cms.CmsException;
14 import org.argeo.node.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;
22
23 class DataModels implements BundleListener {
24 private final static Log log = LogFactory.getLog(DataModels.class);
25
26 private Map<String, DataModel> dataModels = new TreeMap<>();
27
28 public DataModels(BundleContext bc) {
29 for (Bundle bundle : bc.getBundles())
30 processBundle(bundle);
31 bc.addBundleListener(this);
32 }
33
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())
39 res.add(dataModel);
40 }
41 // TODO reorder?
42 return res;
43 }
44
45 @Override
46 public void bundleChanged(BundleEvent event) {
47 if (event.getType() == Bundle.RESOLVED) {
48 processBundle(event.getBundle());
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)
53 return;
54 for (BundleCapability bundleCapability : providedDataModels) {
55 dataModels.remove(bundleCapability.getAttributes().get(DataModelNamespace.NAME));
56 }
57 }
58
59 }
60
61 protected void processBundle(Bundle bundle) {
62 BundleWiring wiring = bundle.adapt(BundleWiring.class);
63 if (wiring == null) {
64 log.warn("Bundle " + bundle.getSymbolicName() + " #" + bundle.getBundleId() + " (" + bundle.getLocation()
65 + ") cannot be adapted to a wiring");
66 return;
67 }
68 List<BundleCapability> providedDataModels = wiring.getCapabilities(CMS_DATA_MODEL_NAMESPACE);
69 if (providedDataModels.size() == 0)
70 return;
71 List<BundleWire> requiredDataModels = wiring.getRequiredWires(CMS_DATA_MODEL_NAMESPACE);
72 // process requirements first
73 for (BundleWire bundleWire : requiredDataModels) {
74 processBundle(bundleWire.getProvider().getBundle());
75 }
76 for (BundleCapability bundleCapability : providedDataModels) {
77 String name = (String) bundleCapability.getAttributes().get(DataModelNamespace.NAME);
78 assert name != null;
79 if (!dataModels.containsKey(name)) {
80 DataModel dataModel = new DataModel(name, bundleCapability, requiredDataModels);
81 dataModels.put(dataModel.getName(), dataModel);
82 }
83 }
84 }
85
86 /** Return a negative depth if dataModel is required by ref, 0 otherwise. */
87 static int required(DataModel ref, DataModel dataModel, int depth) {
88 for (DataModel dm : ref.getRequired()) {
89 if (dm.equals(dataModel))// found here
90 return depth - 1;
91 int d = required(dm, dataModel, depth - 1);
92 if (d != 0)// found deeper
93 return d;
94 }
95 return 0;// not found
96 }
97
98 class DataModel {
99 private final String name;
100 private final boolean abstrct;
101 // private final boolean standalone;
102 private final String cnd;
103 private final List<DataModel> required;
104
105 private DataModel(String name, BundleCapability bundleCapability, List<BundleWire> requiredDataModels) {
106 assert CMS_DATA_MODEL_NAMESPACE.equals(bundleCapability.getNamespace());
107 this.name = name;
108 Map<String, Object> attrs = bundleCapability.getAttributes();
109 abstrct = KernelUtils.asBoolean((String) attrs.get(DataModelNamespace.ABSTRACT));
110 // standalone = KernelUtils.asBoolean((String)
111 // attrs.get(DataModelNamespace.CAPABILITY_STANDALONE_ATTRIBUTE));
112 cnd = (String) attrs.get(DataModelNamespace.CND);
113 List<DataModel> req = new ArrayList<>();
114 for (BundleWire wire : requiredDataModels) {
115 String requiredDataModelName = (String) wire.getCapability().getAttributes()
116 .get(DataModelNamespace.NAME);
117 assert requiredDataModelName != null;
118 DataModel requiredDataModel = dataModels.get(requiredDataModelName);
119 if (requiredDataModel == null)
120 throw new CmsException("No required data model " + requiredDataModelName);
121 req.add(requiredDataModel);
122 }
123 required = Collections.unmodifiableList(req);
124 }
125
126 public String getName() {
127 return name;
128 }
129
130 public boolean isAbstract() {
131 return abstrct;
132 }
133
134 // public boolean isStandalone() {
135 // return !isAbstract();
136 // }
137
138 public String getCnd() {
139 return cnd;
140 }
141
142 public List<DataModel> getRequired() {
143 return required;
144 }
145
146 // @Override
147 // public int compareTo(DataModel o) {
148 // if (equals(o))
149 // return 0;
150 // int res = required(this, o, 0);
151 // if (res != 0)
152 // return res;
153 // // the other way round
154 // res = required(o, this, 0);
155 // if (res != 0)
156 // return -res;
157 // return 0;
158 // }
159
160 @Override
161 public int hashCode() {
162 return name.hashCode();
163 }
164
165 @Override
166 public boolean equals(Object obj) {
167 if (obj instanceof DataModel)
168 return ((DataModel) obj).name.equals(name);
169 return false;
170 }
171
172 @Override
173 public String toString() {
174 return "Data model " + name;
175 }
176
177 }
178
179 }