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