Rename packages in order to make future stable documentation clearer.
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / kernel / DataModels.java
index b758a30637a9aac70d79c5a846618b1fad62455e..acf0dbf7cbf9dbd97e4aa95d26df1c068d7586a1 100644 (file)
@@ -1,6 +1,6 @@
 package org.argeo.cms.internal.kernel;
 
-import static org.argeo.node.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
+import static org.argeo.api.DataModelNamespace.CMS_DATA_MODEL_NAMESPACE;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -8,8 +8,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.api.DataModelNamespace;
 import org.argeo.cms.CmsException;
-import org.argeo.node.DataModelNamespace;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
@@ -19,11 +21,13 @@ import org.osgi.framework.wiring.BundleWire;
 import org.osgi.framework.wiring.BundleWiring;
 
 class DataModels implements BundleListener {
+       private final static Log log = LogFactory.getLog(DataModels.class);
+
        private Map<String, DataModel> dataModels = new TreeMap<>();
 
        public DataModels(BundleContext bc) {
                for (Bundle bundle : bc.getBundles())
-                       processBundle(bundle);
+                       processBundle(bundle, null);
                bc.addBundleListener(this);
        }
 
@@ -41,7 +45,7 @@ class DataModels implements BundleListener {
        @Override
        public void bundleChanged(BundleEvent event) {
                if (event.getType() == Bundle.RESOLVED) {
-                       processBundle(event.getBundle());
+                       processBundle(event.getBundle(), null);
                } else if (event.getType() == Bundle.UNINSTALLED) {
                        BundleWiring wiring = event.getBundle().adapt(BundleWiring.class);
                        List<BundleCapability> providedDataModels = wiring.getCapabilities(CMS_DATA_MODEL_NAMESPACE);
@@ -54,15 +58,41 @@ class DataModels implements BundleListener {
 
        }
 
-       protected void processBundle(Bundle bundle) {
+       protected void processBundle(Bundle bundle, List<Bundle> scannedBundles) {
+               if (scannedBundles != null && scannedBundles.contains(bundle))
+                       throw new IllegalStateException("Cycle in CMS data model requirements for " + bundle);
                BundleWiring wiring = bundle.adapt(BundleWiring.class);
+               if (wiring == null) {
+                       int bundleState = bundle.getState();
+                       if (bundleState != Bundle.INSTALLED && bundleState != Bundle.UNINSTALLED) {// ignore unresolved bundles
+                               log.warn("Bundle " + bundle.getSymbolicName() + " #" + bundle.getBundleId() + " ("
+                                               + bundle.getLocation() + ") cannot be adapted to a wiring");
+                       } else {
+                               if (log.isTraceEnabled())
+                                       log.warn("Bundle " + bundle.getSymbolicName() + " is not resolved.");
+                       }
+                       return;
+               }
                List<BundleCapability> providedDataModels = wiring.getCapabilities(CMS_DATA_MODEL_NAMESPACE);
                if (providedDataModels.size() == 0)
                        return;
                List<BundleWire> requiredDataModels = wiring.getRequiredWires(CMS_DATA_MODEL_NAMESPACE);
+               // process requirements first
+               for (BundleWire bundleWire : requiredDataModels) {
+                       List<Bundle> nextScannedBundles = new ArrayList<>();
+                       if (scannedBundles != null)
+                               nextScannedBundles.addAll(scannedBundles);
+                       nextScannedBundles.add(bundle);
+                       Bundle providerBundle = bundleWire.getProvider().getBundle();
+                       processBundle(providerBundle, nextScannedBundles);
+               }
                for (BundleCapability bundleCapability : providedDataModels) {
-                       DataModel dataModel = new DataModel(bundleCapability, requiredDataModels);
-                       dataModels.put(dataModel.getName(), dataModel);
+                       String name = (String) bundleCapability.getAttributes().get(DataModelNamespace.NAME);
+                       assert name != null;
+                       if (!dataModels.containsKey(name)) {
+                               DataModel dataModel = new DataModel(name, bundleCapability, requiredDataModels);
+                               dataModels.put(dataModel.getName(), dataModel);
+                       }
                }
        }
 
@@ -85,11 +115,10 @@ class DataModels implements BundleListener {
                private final String cnd;
                private final List<DataModel> required;
 
-               private DataModel(BundleCapability bundleCapability, List<BundleWire> requiredDataModels) {
+               private DataModel(String name, BundleCapability bundleCapability, List<BundleWire> requiredDataModels) {
                        assert CMS_DATA_MODEL_NAMESPACE.equals(bundleCapability.getNamespace());
+                       this.name = name;
                        Map<String, Object> attrs = bundleCapability.getAttributes();
-                       name = (String) attrs.get(DataModelNamespace.NAME);
-                       assert name != null;
                        abstrct = KernelUtils.asBoolean((String) attrs.get(DataModelNamespace.ABSTRACT));
                        // standalone = KernelUtils.asBoolean((String)
                        // attrs.get(DataModelNamespace.CAPABILITY_STANDALONE_ATTRIBUTE));