felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From clem...@apache.org
Subject svn commit: r629469 [2/2] - in /felix/sandbox/clement/ipojo: composite/src/main/java/org/apache/felix/ipojo/composite/service/importer/ composite/src/main/java/org/apache/felix/ipojo/composite/service/instantiator/ composite/src/main/java/org/apache/fe...
Date Wed, 20 Feb 2008 14:23:37 GMT
Modified: felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java?rev=629469&r1=629468&r2=629469&view=diff
==============================================================================
--- felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java (original)
+++ felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyCallback.java Wed Feb 20 06:23:33 2008
@@ -139,7 +139,7 @@
     }
     
     /**
-     * Introspaect parent class to find the method.
+     * Introspect parent class to find the method.
      */
     private void searchParentMethod() {
         // look at parent classes
@@ -162,18 +162,18 @@
                             m_argument = new String[] { ServiceReference.class.getName() };
                             return;
                         }
-                        if (clazzes[0].getName().equals(m_dependency.getSpecification())) {
+                        if (clazzes[0].getName().equals(m_dependency.getSpecification().getName())) {
                             // Callback with the service object.
                             m_methodObj = methods[i];
-                            m_argument = new String[] { m_dependency.getSpecification() };
+                            m_argument = new String[] { m_dependency.getSpecification().getName() };
                             return;
                         }
                         break;
                     case 2:
-                        if (clazzes[0].getName().equals(m_dependency.getSpecification()) && clazzes[1].getName().equals(ServiceReference.class.getName())) {
+                        if (clazzes[0].getName().equals(m_dependency.getSpecification().getName()) && clazzes[1].getName().equals(ServiceReference.class.getName())) {
                             // Callback with two arguments.
                             m_methodObj = methods[i];
-                            m_argument = new String[] { m_dependency.getSpecification(), ServiceReference.class.getName() };
+                            m_argument = new String[] { m_dependency.getSpecification().getName(), ServiceReference.class.getName() };
                             return;
                         }
                         break;

Modified: felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java?rev=629469&r1=629468&r2=629469&view=diff
==============================================================================
--- felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java (original)
+++ felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyDescription.java Wed Feb 20 06:23:33 2008
@@ -79,7 +79,6 @@
         m_optional = optional;
         m_filter = filter;
         m_state = state;
-        m_serviceReferences = new ArrayList();
     }
 
     public boolean isMultiple() { return m_multiple; }

Modified: felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java?rev=629469&r1=629468&r2=629469&view=diff
==============================================================================
--- felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java (original)
+++ felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java Wed Feb 20 06:23:33 2008
@@ -20,11 +20,12 @@
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.Dictionary;
 import java.util.List;
 
-import org.apache.felix.ipojo.ComponentInstance;
 import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.IPojoContext;
 import org.apache.felix.ipojo.PolicyServiceContext;
 import org.apache.felix.ipojo.PrimitiveHandler;
 import org.apache.felix.ipojo.architecture.HandlerDescription;
@@ -32,6 +33,10 @@
 import org.apache.felix.ipojo.parser.FieldMetadata;
 import org.apache.felix.ipojo.parser.MethodMetadata;
 import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.AbstractServiceDependency;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 
 /**
@@ -80,7 +85,7 @@
      * Check the validity of the dependencies.
      */
     protected void checkContext() {
-        if (! m_started) { return; }
+        if (!m_started) { return; }
         synchronized (m_dependencies) {
             // Store the initial state
             boolean initialState = getValidity();
@@ -88,12 +93,12 @@
             boolean valid = true;
             for (int i = 0; i < m_dependencies.length; i++) {
                 Dependency dep = m_dependencies[i];
-                if (dep.getState() > Dependency.RESOLVED) { 
+                if (dep.getState() != Dependency.RESOLVED) {
                     valid = false;
                     break;
                 }
             }
-            
+
             // Check the component dependencies
             if (valid) {
                 // The dependencies are valid
@@ -115,8 +120,7 @@
     }
 
     /**
-     * Check if the dependency given is valid in the sense that metadata are
-     * consistent.
+     * Check if the dependency given is valid in the sense that metadata are consistent.
      * @param dep : the dependency to check
      * @param manipulation : the component-type manipulation metadata
      * @return true if the dependency is valid
@@ -126,27 +130,33 @@
         // Check the internal type of dependency
         String field = dep.getField();
         DependencyCallback[] callbacks = dep.getCallbacks();
-        
-        if (callbacks.length == 0 && field == null) {
-            throw new ConfigurationException("A service requirement requires at least callbacks or a field");
-        }
+
+        if (callbacks.length == 0 && field == null) { throw new ConfigurationException("A service requirement requires at least callbacks or a field"); }
 
         for (int i = 0; i < callbacks.length; i++) {
             MethodMetadata[] mets = manipulation.getMethods(callbacks[i].getMethodName());
             if (mets.length != 0) {
-                if (mets[0].getMethodArguments().length > 2) {
-                    throw new ConfigurationException("Requirement Callback : A requirement callback " + callbacks[i].getMethodName() + " must have 0 or 1 or 2 arguments");
-                }
-                
+                if (mets[0].getMethodArguments().length > 2) { throw new ConfigurationException("Requirement Callback : A requirement callback " + callbacks[i].getMethodName() + " must have 0 or 1 or 2 arguments"); }
+
                 callbacks[i].setArgument(mets[0].getMethodArguments());
                 if (mets[0].getMethodArguments().length == 1) {
                     if (!mets[0].getMethodArguments()[0].equals(ServiceReference.class.getName())) {
                         if (dep.getSpecification() == null) {
-                            dep.setSpecification(mets[0].getMethodArguments()[0]);
+                            try {
+                                dep.setSpecification(getInstanceManager().getContext().getBundle().loadClass(mets[0].getMethodArguments()[0]));
+                            } catch (ClassNotFoundException e) {
+                                // TODO Auto-generated catch block
+                                e.printStackTrace();
+                            }
                         }
-                        if (!dep.getSpecification().equals(mets[0].getMethodArguments()[0])) {
+                        if (!dep.getSpecification().getName().equals(mets[0].getMethodArguments()[0])) {
                             warn("[DependencyHandler on " + getInstanceManager().getInstanceName() + "] The field type [" + mets[0].getMethodArguments()[0] + "] and the needed service interface [" + dep.getSpecification() + "] are not the same");
-                            dep.setSpecification(mets[0].getMethodArguments()[0]);
+                            try {
+                                dep.setSpecification(getInstanceManager().getContext().getBundle().loadClass(mets[0].getMethodArguments()[0]));
+                            } catch (ClassNotFoundException e) {
+                                // TODO Auto-generated catch block
+                                e.printStackTrace();
+                            }
                         }
                     }
                 } else if (mets[0].getMethodArguments().length == 2) {
@@ -156,11 +166,21 @@
                         throw new ConfigurationException(message);
                     }
                     if (dep.getSpecification() == null) {
-                        dep.setSpecification(mets[0].getMethodArguments()[0]);
+                        try {
+                            dep.setSpecification(getInstanceManager().getContext().getBundle().loadClass(mets[0].getMethodArguments()[0]));
+                        } catch (ClassNotFoundException e) {
+                            // TODO Auto-generated catch block
+                            e.printStackTrace();
+                        }
                     } else {
-                        if (!dep.getSpecification().equals(mets[0].getMethodArguments()[0])) {
+                        if (!dep.getSpecification().getName().equals(mets[0].getMethodArguments()[0])) {
                             warn("[DependencyHandler on " + getInstanceManager().getInstanceName() + "] The field type [" + mets[0].getMethodArguments()[0] + "] and the needed service interface [" + dep.getSpecification() + "] are not the same");
-                            dep.setSpecification(mets[0].getMethodArguments()[0]);
+                            try {
+                                dep.setSpecification(getInstanceManager().getContext().getBundle().loadClass(mets[0].getMethodArguments()[0]));
+                            } catch (ClassNotFoundException e) {
+                                // TODO Auto-generated catch block
+                                e.printStackTrace();
+                            }
                         }
                     }
                 }
@@ -172,28 +192,27 @@
 
         if (field != null) {
             FieldMetadata fm = manipulation.getField(field);
-            if (fm == null) {
-                throw new ConfigurationException("Requirement Callback : A requirement field " + field + " does not exist in the implementation class");
-            }
+            if (fm == null) { throw new ConfigurationException("Requirement Callback : A requirement field " + field + " does not exist in the implementation class"); }
             String type = fm.getFieldType();
             if (type.endsWith("[]")) {
                 // Set the dependency to multiple
-                dep.setAggregate();
+                dep.setAggregate(true);
                 type = type.substring(0, type.length() - 2);
             } else {
-                if (dep.isAggregate()) {
-                    throw new ConfigurationException("A required service is not correct : the field " + fm.getFieldName() + " must be an array to support aggregate injections");
-                }
+                if (dep.isAggregate()) { throw new ConfigurationException("A required service is not correct : the field " + fm.getFieldName() + " must be an array to support aggregate injections"); }
             }
 
             if (dep.getSpecification() == null) {
-                dep.setSpecification(type);
-            } else if (!dep.getSpecification().equals(type)) {
-                throw new ConfigurationException("A required service is not correct : the field type [" + type + "] and the needed service interface [" + dep.getSpecification() + "] are not the same");
-            }
+                try {
+                    dep.setSpecification(getInstanceManager().getContext().getBundle().loadClass(type));
+                } catch (ClassNotFoundException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            } else if (!dep.getSpecification().getName().equals(type)) { throw new ConfigurationException("A required service is not correct : the field type [" + type + "] and the needed service interface [" + dep.getSpecification().getName() + "] are not the same"); }
         }
 
-        //Check that all required info are set
+        // Check that all required info are set
         return dep.getSpecification() != null;
     }
 
@@ -215,7 +234,7 @@
 
         // Get instance filters.
         Dictionary filtersConfiguration = (Dictionary) configuration.get("requires.filters");
-        
+
         for (int i = 0; deps != null && i < deps.length; i++) {
             // Create the dependency metadata
             String field = deps[i].getAttribute("field");
@@ -224,20 +243,21 @@
             String opt = deps[i].getAttribute("optional");
             boolean optional = opt != null && opt.equalsIgnoreCase("true");
             String di = deps[i].getAttribute("default-implementation");
-            
+
             String agg = deps[i].getAttribute("aggregate");
             boolean aggregate = agg != null && agg.equalsIgnoreCase("true");
             String id = deps[i].getAttribute("id");
 
-            int scopePolicy = -1;
-            String scope = deps[i].getAttribute("scope"); 
+            String scope = deps[i].getAttribute("scope");
+            BundleContext bc = getInstanceManager().getContext(); // Get the default bundle context.
             if (scope != null) {
-                if (scope.equalsIgnoreCase("global")) {
-                    scopePolicy = PolicyServiceContext.GLOBAL;
+                // If we are not in a composite, the policy is set to global.
+                if (scope.equalsIgnoreCase("global") || ((((IPojoContext) getInstanceManager().getContext()).getServiceContext()) == null)) {
+                    bc = new PolicyServiceContext(getInstanceManager().getGlobalContext(), getInstanceManager().getLocalServiceContext(), PolicyServiceContext.GLOBAL);
                 } else if (scope.equalsIgnoreCase("composite")) {
-                    scopePolicy = PolicyServiceContext.LOCAL;
+                    bc = new PolicyServiceContext(getInstanceManager().getGlobalContext(), getInstanceManager().getLocalServiceContext(), PolicyServiceContext.LOCAL);
                 } else if (scope.equalsIgnoreCase("composite+global")) {
-                    scopePolicy = PolicyServiceContext.LOCAL_AND_GLOBAL;
+                    bc = new PolicyServiceContext(getInstanceManager().getGlobalContext(), getInstanceManager().getLocalServiceContext(), PolicyServiceContext.LOCAL_AND_GLOBAL);
                 }
             }
 
@@ -245,29 +265,29 @@
             if (filtersConfiguration != null && id != null && filtersConfiguration.get(id) != null) {
                 filter = (String) filtersConfiguration.get(id);
             }
-            
-            
-            // Parse binding policy
-            int bindingPolicy = Dependency.DYNAMIC_POLICY;
-            String policy = deps[i].getAttribute("policy"); 
-            if (policy != null) {
-                if (policy.equalsIgnoreCase("static")) {
-                    bindingPolicy = Dependency.STATIC_POLICY;
-                } else if (policy.equalsIgnoreCase("dynamic")) {
-                    bindingPolicy = Dependency.DYNAMIC_POLICY;
-                } else if (policy.equalsIgnoreCase("dynamic-priority")) {
-                    bindingPolicy = Dependency.DYNAMIC_PRIORITY_POLICY;
+
+            Filter fil = null;
+            if (filter != null) { 
+                try {
+                    fil = getInstanceManager().getContext().createFilter(filter);
+                } catch (InvalidSyntaxException e) {
+                    throw new ConfigurationException("A requirement filter is invalid : " + filter + " - " + e.getMessage());
                 }
             }
+
+            Class spec = null;
+            if (serviceSpecification != null) {
+                spec = AbstractServiceDependency.loadSpecification(serviceSpecification, getInstanceManager().getContext());
+            }
             
-            Dependency dep = new Dependency(this, field, serviceSpecification, filter, optional, aggregate, id, scopePolicy, bindingPolicy, di);
+            int policy = AbstractServiceDependency.getPolicy(deps[i]);            
+            Comparator cmp = AbstractServiceDependency.getComparator(deps[i], getInstanceManager().getGlobalContext());
+            Dependency dep = new Dependency(this, field, spec, fil, optional, aggregate, id, bc, policy, cmp, di);
 
             // Look for dependency callback :
             Element[] cbs = deps[i].getElements("Callback");
             for (int j = 0; cbs != null && j < cbs.length; j++) {
-                if (!cbs[j].containsAttribute("method") && cbs[j].containsAttribute("type")) { 
-                    throw new ConfigurationException("Requirement Callback : a dependency callback must contain a method and a type attribute"); 
-                }
+                if (!cbs[j].containsAttribute("method") && cbs[j].containsAttribute("type")) { throw new ConfigurationException("Requirement Callback : a dependency callback must contain a method and a type attribute"); }
                 String method = cbs[j].getAttribute("method");
                 String type = cbs[j].getAttribute("type");
                 int methodType = 0;
@@ -348,7 +368,7 @@
             }
         }
     }
-    
+
     /**
      * Method Error callback.
      * @param pojo : the pojo object on which the field is accessed
@@ -393,27 +413,13 @@
     }
 
     /**
-     * Handler createInstance method.
-     * This method is override to allow delayed callback invocation.
+     * Handler createInstance method. This method is override to allow delayed callback invocation.
      * @param instance : the created object
      * @see org.apache.felix.ipojo.Handler#onCreation(java.lang.Object)
      */
     public void onCreation(Object instance) {
         for (int i = 0; i < m_dependencies.length; i++) {
-            m_dependencies[i].callBindMethod(instance);
-        }
-    }
-    
-    /**
-     * The instance state changes. If the new state is valid, we need to activate dependencies.
-     * @param state : the new state
-     * @see org.apache.felix.ipojo.Handler#stateChanged(int)
-     */
-    public void stateChanged(int state) {
-        if (state == ComponentInstance.VALID) {
-            for (int i = 0; i < m_dependencies.length; i++) {
-                m_dependencies[i].activate();
-            }
+            m_dependencies[i].onObjectCreation(instance);
         }
     }
 
@@ -427,9 +433,9 @@
         for (int j = 0; j < getDependencies().length; j++) {
             Dependency dep = getDependencies()[j];
             // Create & add the dependency description
-            DependencyDescription dd = new DependencyDescription(dep.getSpecification(), dep.isAggregate(), dep.isOptional(), dep.getFilter(), dep.getState());
-            dd.setServiceReferences(dep.getServiceReferences());
-            dd.setUsedServices(dep.getUsedServices());
+            DependencyDescription dd = new DependencyDescription(dep.getSpecification().getName(), dep.isAggregate(), dep.isOptional(), dep.getFilter(), dep.getState());
+            dd.setServiceReferences(dep.getServiceReferencesAsList());
+            dd.setUsedServices(dep.getUsedServiceReferences());
             dhd.addDependency(dd);
         }
         return dhd;

Modified: felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java?rev=629469&r1=629468&r2=629469&view=diff
==============================================================================
--- felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java (original)
+++ felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java Wed Feb 20 06:23:33 2008
@@ -52,7 +52,7 @@
         Element[] elems = m_elements[0].getElements();
         List list = new ArrayList();
         for (int i = 0; i < elems.length; i++) {
-            if (! "instance".equals( elems[i].getName() )) {
+            if (! "instance".equals(elems[i].getName())) {
                 list.add(elems[i]);
             }
         }

Added: felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/util/AbstractServiceDependency.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/util/AbstractServiceDependency.java?rev=629469&view=auto
==============================================================================
--- felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/util/AbstractServiceDependency.java (added)
+++ felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/util/AbstractServiceDependency.java Wed Feb 20 06:23:33 2008
@@ -0,0 +1,750 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Abstract dependency model. This class is the parent class of every service dependency. It manages the most part of dependency management. This class creates an insterface between the service tracker and the concrete dependency.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class AbstractServiceDependency implements TrackerCustomizer {
+
+    /**
+     * Dependency state : BROKEN. A broken dependency cannot be fulfilled anymore. The dependency becomes broken when a used service disappears in the static binding policy.
+     */
+    public static final int BROKEN = -1;
+
+    /**
+     * Dependency state : UNRESOLVED. A dependency is unresolved if the dependency is not valid and no service providers are available.
+     */
+    public static final int UNRESOLVED = 0;
+
+    /**
+     * Dependency state : RESOLVED. A dependency is resolved if the dependency is optional or at least one provider is available.
+     */
+    public static final int RESOLVED = 1;
+
+    /**
+     * Binding policy : Dynamic. In this policy, services can appears and departs without special treatment.
+     */
+    public static final int DYNAMIC_BINDING_POLICY = 0;
+
+    /**
+     * Binding policy : Static. Once a service is used, if this service disappears the dependency becomes BROKEN. The instance needs to be recreated.
+     */
+    public static final int STATIC_BINDING_POLICY = 1;
+
+    /**
+     * Binding policy : Dynamic-Priority. In this policy, services can appears and departs. However, once a service with a highest ranking (according to the used comparator) appears, this new service is re-injected.
+     */
+    public static final int DYNAMIC_PRIORITY_BINDING_POLICY = 2;
+
+    /**
+     * Does the dependency bind several providers ?
+     */
+    private boolean m_aggregate;
+
+    /**
+     * Is the dependency optional ?
+     */
+    private boolean m_optional;
+
+    /**
+     * Required specification. Cannot change once set.
+     */
+    private Class m_specification;
+
+    /**
+     * Comparator to sort service references.
+     */
+    private Comparator m_comparator;
+
+    /**
+     * LDAP filter object selecting service references form the set of providers providing the required specification.
+     */
+    private Filter m_filter;
+
+    /**
+     * Bundle context used by the dependency. (could be a service context).
+     */
+    private BundleContext m_context;
+
+    /**
+     * Actual state of the dependency.
+     */
+    private int m_state;
+
+    /**
+     * Binding policy of the dependency.
+     */
+    private int m_policy = DYNAMIC_BINDING_POLICY;
+
+    /**
+     * Service tracker used by this dependency.
+     */
+    private Tracker m_tracker;
+
+    /**
+     * List of matching service references. This list is a subset of tracked references. This set is compute according to the filter and the match method.
+     */
+    private List m_matchingReferences = new ArrayList();
+
+    /**
+     * Constructor.
+     * @param specification : required specification
+     * @param aggregate : is the dependency aggregate ?
+     * @param optional : is the dependency optional ?
+     * @param filter : LDAP filter
+     * @param comparator : comparator object to sort references
+     * @param policy : binding policy
+     * @param context : bundle context (or service context)
+     */
+    public AbstractServiceDependency(Class specification, boolean aggregate, boolean optional, Filter filter, Comparator comparator, int policy, BundleContext context) {
+        m_specification = specification;
+        m_aggregate = aggregate;
+        m_optional = optional;
+        m_filter = filter;
+        m_comparator = comparator;
+        m_context = context;
+        m_policy = policy;
+        // If the dynamic priority policy is chosen, and we have no comparator, fix it to OSGi standard service reference comparator.
+        if (m_policy == DYNAMIC_PRIORITY_BINDING_POLICY && m_comparator == null) {
+            m_comparator = new ServiceReferenceRankingComparator();
+        }
+        m_state = UNRESOLVED;
+    }
+
+    /**
+     * Open the tracking.
+     */
+    public void start() {
+        m_tracker = new Tracker(m_context, m_specification.getName(), this);
+        m_tracker.open();
+        computeDependencyState();
+    }
+
+    /**
+     * Close the tracking.
+     */
+    public void stop() {
+        m_tracker.close();
+        m_tracker = null;
+        m_state = UNRESOLVED;
+    }
+
+    /**
+     * Is the reference set frozen (cannot change anymore) ? This method must be override by concrete dependency to support the static binding policy. This method is just used by default. The method must always return false for non-static dependency.
+     * @return true if the reference set is frozen.
+     */
+    public boolean isFrozen() {
+        return false;
+    }
+
+    /**
+     * Does the service reference match ? This method must be override by concrete dependency if they need to advanced testing on service reference (that cannot be express in the LDAP filter). By default this method return true.
+     * @param ref : tested reference.
+     * @return true
+     */
+    public boolean match(ServiceReference ref) {
+        return true;
+    }
+
+    /**
+     * Compute the actual dependency state.
+     */
+    private void computeDependencyState() {
+        if (m_state == BROKEN) { return; } // The dependency is broken ...
+
+        boolean mustCallValidate = false;
+        boolean mustCallInvalidate = false;
+        synchronized (this) {
+            if (m_optional || m_matchingReferences.size() > 0) {
+                // The dependency is valid
+                if (m_state == UNRESOLVED) {
+                    m_state = RESOLVED;
+                    mustCallValidate = true;
+                }
+            } else {
+                // The dependency is invalid
+                if (m_state == RESOLVED) {
+                    m_state = UNRESOLVED;
+                    mustCallInvalidate = true;
+                }
+            }
+        }
+
+        // Invoke callback in a non-synchronized region
+        if (mustCallInvalidate) {
+            invalidate();
+        } else if (mustCallValidate) {
+            validate();
+        }
+
+    }
+
+    /**
+     * Service tracker adding service callback. We accept the service only if we aren't broken or frozen.
+     * @param ref : the new dependency.
+     * @return true if the reference must be tracked.
+     * @see org.apache.felix.ipojo.util.TrackerCustomizer#addingService(org.osgi.framework.ServiceReference)
+     */
+    public boolean addingService(ServiceReference ref) {
+        return !((m_state == BROKEN) || isFrozen());
+    }
+
+    /**
+     * Service Tracker added service callback. If the service matches, manage the arrival.
+     * @param ref : new references.
+     * @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)
+     */
+    public void addedService(ServiceReference ref) {
+        if ((m_filter == null || m_filter.match(ref)) && match(ref)) {
+            manageArrival(ref);
+        }
+        // Do not store the service if it doesn't match.
+    }
+
+    /**
+     * Manage the arrival of a new service reference. The reference is valid and match the filter and the match method. This method has different behavior according to the binding policy.
+     * @param ref : the new reference
+     */
+    private void manageArrival(ServiceReference ref) {
+
+        // Create a local copy of the state and of the list size.
+        int state = m_state;
+        int size;
+
+        synchronized (this) {
+            m_matchingReferences.add(ref);
+
+            // Sort the collection if needed.
+            if (m_comparator != null) {
+                Collections.sort(m_matchingReferences, m_comparator);
+            }
+
+            size = m_matchingReferences.size();
+        }
+
+        if (m_aggregate) {
+            onServiceArrival(ref); // Always notify the arrival for aggregate dependencies.
+            if (state == UNRESOLVED) { // If we was unresolved, try to validate the dependency.
+                computeDependencyState();
+            }
+        } else { // We are not aggregate.
+            if (size == 1) {
+                onServiceArrival(ref); // It is the first service, so notify.
+                computeDependencyState();
+            } else {
+                // In the case of a dynamic priority binding, we have to test if we have to update the bound reference
+                if (m_policy == DYNAMIC_PRIORITY_BINDING_POLICY && m_matchingReferences.get(0) == ref) {
+                    // We are sure that we have at least two references, so if the highest ranked references (first one) is the new received references,
+                    // we have to unbind the used one and to bind the the new one.
+                    onServiceDeparture((ServiceReference) m_matchingReferences.get(1));
+                    onServiceArrival(ref);
+                }
+            }
+        }
+        // Ignore others cases
+    }
+
+    /**
+     * Service tracker removed service callback. A service goes away. The depart need to be managed only if the reference was used.
+     * @param ref : leaving service reference
+     * @param arg1 : service object if the service was get
+     * @see org.apache.felix.ipojo.util.TrackerCustomizer#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
+     */
+    public void removedService(ServiceReference ref, Object arg1) {
+        if (m_matchingReferences.contains(ref)) {
+            manageDeparture(ref, arg1);
+        }
+    }
+
+    /**
+     * Manage the departure of a used service.
+     * @param ref : leaving service reference
+     * @param obj : service object if the service was get
+     */
+    private void manageDeparture(ServiceReference ref, Object obj) {
+        // If we already get this service and the binding policy is static, the dependency becomes broken
+        if (isFrozen() && obj != null) {
+            if (m_state != BROKEN) {
+                m_state = BROKEN;
+                invalidate();
+            }
+        } else {
+            synchronized (this) {
+                m_matchingReferences.remove(ref);
+            }
+            if (obj != null) {
+                onServiceDeparture(ref);
+                ServiceReference newRef = getServiceReference();
+                if (newRef != null) { // Check if there is another provider.
+                    if (!m_aggregate) {
+                        onServiceArrival(newRef); // Injecting the new service reference for non aggregate dependencies.
+                    }
+                } else {
+                    computeDependencyState(); // no more references.
+                }
+            } else {
+                computeDependencyState(); // check if the dependency stills valid.
+            }
+        }
+
+    }
+
+    /**
+     * Service tracker modified service callback. This method must handle if the modified service should be considered as a depart or an arrival. According to the dependency filter, a service can now match or can no match anymore.
+     * @param ref : modified reference
+     * @param arg1 : service object if already get.
+     * @see org.apache.felix.ipojo.util.TrackerCustomizer#modifiedService(org.osgi.framework.ServiceReference, java.lang.Object)
+     */
+    public void modifiedService(ServiceReference ref, Object arg1) {
+        if (m_matchingReferences.contains(ref)) {
+            // It's a used service. Check if the service always match.
+            if (!(m_filter == null || m_filter.match(ref)) && match(ref)) {
+                // The service does not match anymore. Call removedService.
+                manageDeparture(ref, arg1);
+            }
+            // If the service match, nothing to do.
+        } else {
+            // The service was not used. Check if it matches.
+            if ((m_filter == null || m_filter.match(ref)) && match(ref)) {
+                manageArrival(ref);
+            }
+            // Else, the service does not match.
+        }
+    }
+
+    /**
+     * Get the next matching service reference.
+     * @return null if no more provider is available, else return the first reference from the matching set.
+     */
+    public synchronized ServiceReference getServiceReference() {
+        if (m_matchingReferences.isEmpty()) {
+            return null;
+        } else {
+            return (ServiceReference) m_matchingReferences.get(0);
+        }
+    }
+    
+    /**
+     * Get matching service references. 
+     * @return the sorted (if a comparator is used) array of matching service references, null if no references are available. 
+     */
+    public synchronized ServiceReference[] getServiceReferences() {
+        if (m_matchingReferences.isEmpty()) { return null; }
+        return (ServiceReference[]) m_matchingReferences.toArray(new ServiceReference[m_matchingReferences.size()]);
+    }
+    
+
+    /**
+     * Get the list of currently used service references.
+     * @return the list of used reference (according to the service tracker).
+     */
+    public List getUsedServiceReferences() {
+        return m_tracker.getUsedServiceReferences();
+        //TODO : does this method support dependency reconfiguration ?
+    }
+
+    /**
+     * Get the number of actual matching references.
+     * @return the number of matching references
+     */
+    public int getSize() {
+        return m_matchingReferences.size();
+    }
+
+    /**
+     * Concrete dependency callback. This method is called when a new service need to be re-injected in the underlying concrete dependency.
+     * @param ref : service reference to inject.
+     */
+    public abstract void onServiceArrival(ServiceReference ref);
+
+    /**
+     * Concrete dependency callback. This method is called when a used service (already injected) is leaving.
+     * @param ref : the leaving service reference.
+     */
+    public abstract void onServiceDeparture(ServiceReference ref);
+
+    /**
+     * Concrete dependency callback. This method is called when the dependency is reconfigured and when this reconfiguration implies changes on the matching service set ( and by the way on the injected service).
+     * @param departs : service leaving the matching set.
+     * @param arrivals : service arriving in the matching set.
+     */
+    public abstract void onDependencyReconfiguration(ServiceReference[] departs, ServiceReference[] arrivals);
+
+    /**
+     * Concrete dependency callback. This method is called when the dependency becomes unresolved or broken.
+     */
+    public abstract void invalidate();
+
+    /**
+     * Concrete dependency callback. This method is called when the dependency becomes resolved.
+     */
+    public abstract void validate();
+
+    /**
+     * Get the actual state of the dependency.
+     * @return : the state of the dependency.
+     */
+    public int getState() {
+        return m_state;
+    }
+
+    /**
+     * Get the tracked specification.
+     * @return the Class object tracked by the dependency.
+     */
+    public Class getSpecification() {
+        return m_specification;
+    }
+
+    /**
+     * Set the required specification of this service dependency. This operation is not supported if the dependency tracking has already begun.
+     * @param specification : required specification.
+     */
+    public void setSpecification(Class specification) {
+        if (m_tracker == null) {
+            m_specification = specification;
+        } else {
+            throw new UnsupportedOperationException("Dynamic specification change is not yet supported");
+        }
+    }
+
+    /**
+     * Set the filter of the dependency. This method recompute the matching set and call the onDependencyReconfiguration callback.
+     * @param filter : new LDAP filter.
+     */
+    public void setFilter(Filter filter) {
+        m_filter = filter;
+        if (m_tracker != null) { // Tracking started ...
+            List toRemove = new ArrayList();
+            List toAdd = new ArrayList();
+            ServiceReference usedRef = null;
+            synchronized (this) {
+
+                // Store the used service references.
+                if (!m_aggregate && m_matchingReferences.size() > 0) {
+                    usedRef = (ServiceReference) m_matchingReferences.get(0);
+                }
+
+                // Get actually all tracked references.
+                ServiceReference[] refs = m_tracker.getServiceReferences();
+
+                if (refs != null) {
+                    // Compute matching services.
+                    List matching = new ArrayList();
+                    for (int i = 0; i < refs.length; i++) {
+                        if (m_filter == null || m_filter.match(refs[i]) && match(refs[i])) {
+                            matching.add(refs[i]);
+                        }
+                    }
+                    // Now compare with used services.
+                    for (int j = 0; j < m_matchingReferences.size(); j++) {
+                        ServiceReference ref = (ServiceReference) m_matchingReferences.get(j);
+                        // Check if the reference is inside the matching list:
+                        if (!matching.contains(ref)) {
+                            // The reference should be removed.
+                            toRemove.add(ref);
+                        }
+                    }
+
+                    // Then remove services which do no more match.
+                    m_matchingReferences.removeAll(toRemove);
+
+                    // Then, add new matching services.
+
+                    for (int k = 0; k < matching.size(); k++) {
+                        if (!m_matchingReferences.contains(matching.get(k))) {
+                            m_matchingReferences.add(matching.get(k));
+                            toAdd.add(matching.get(k));
+                        }
+                    }
+                    
+                    // Sort the collections if needed.
+                    if (m_comparator != null) {
+                        Collections.sort(m_matchingReferences, m_comparator);
+                        Collections.sort(toAdd, m_comparator);
+                        Collections.sort(toRemove, m_comparator);
+                    }
+                    
+                } else {
+                    for (int j = 0; j < m_matchingReferences.size(); j++) {
+                        // All references need to be removed.
+                        toRemove.add(m_matchingReferences.get(j));
+                    }
+                    // No more matching dependency. Clear the matching reference set.
+                    m_matchingReferences.clear();
+                }
+            }
+
+            // Call the callback outside the sync bloc.
+            if (m_aggregate) {
+                ServiceReference[] rem = null;
+                ServiceReference[] add = null;
+                if (toAdd.size() > 0) {
+                    add = (ServiceReference[]) toAdd.toArray(new ServiceReference[toAdd.size()]);
+                }
+                if (toRemove.size() > 0) {
+                    rem = (ServiceReference[]) toRemove.toArray(new ServiceReference[toRemove.size()]);
+                }
+                onDependencyReconfiguration(rem, add); //TODO : In the case where both set are null, does we notify no change ? 
+            } else {
+                // Create a local copy to avoid un-sync reference list access. 
+                int size;
+                ServiceReference newRef;
+                synchronized (m_matchingReferences) {
+                    size = m_matchingReferences.size();
+                    newRef = (ServiceReference) m_matchingReferences.get(0);
+                }
+                // Non aggregate case.
+                // If the used reference was not null 
+                if (usedRef != null) {
+                    // If the used ref disappears, inject a new service if available, else reinject null.
+                    if (toRemove.contains(usedRef)) {
+                        // We have to replace the service.
+                        if (size > 0) {
+                            onDependencyReconfiguration(new ServiceReference[] {usedRef}, new ServiceReference[] {newRef});
+                        } else {
+                            onDependencyReconfiguration(new ServiceReference[] {usedRef}, null);
+                        }
+                    } else if (m_policy == DYNAMIC_PRIORITY_BINDING_POLICY) {
+                        // In the case of dynamic-priority, check if the used ref is no more the highest reference
+                        if (newRef != usedRef) {
+                            onDependencyReconfiguration(new ServiceReference[] {usedRef}, new ServiceReference[] {newRef});
+                        }
+                    }
+                } else {
+                    // The used ref was null, 
+                    if (size > 0) {
+                        onDependencyReconfiguration(null, new ServiceReference[] {newRef});
+                    } else {
+                        // TODO : Is is really useful : notify no change ?
+                        onDependencyReconfiguration(null, null);
+                    }
+                }
+            }
+            // Now, compute the new dependency state.
+            computeDependencyState();
+        }
+    }
+
+    /**
+     * Return the dependency filter (String form).
+     * @return the String form of the LDAP filter used by this dependency, null if not set.
+     */
+    public String getFilter() {
+        if (m_filter != null) {
+            return m_filter.toString();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set the aggregate attribute of the current dependency.
+     * If the tracking is open, it will call arrival and 
+     * departure callbacks.
+     * @param isAggregate : new aggregate attribute value.
+     */
+    public synchronized void setAggregate(boolean isAggregate) {
+        if (m_tracker == null) { // Not started ...
+            m_aggregate = isAggregate;
+        } else {
+            // We become aggregate.
+            if (!m_aggregate && isAggregate) {
+                m_aggregate = true;
+                // Call the callback on all non already injected service.
+                if (m_state == RESOLVED) {
+
+                    for (int i = 1; i < m_matchingReferences.size(); i++) { // The loop begin at 1, as the 0 is already injected.
+                        onServiceArrival((ServiceReference) m_matchingReferences.get(i));
+                    }
+                }
+            } else if (m_aggregate && !isAggregate) {
+                m_aggregate = false;
+                // We become non-aggregate.
+                if (m_state == RESOLVED) {
+                    for (int i = 1; i < m_matchingReferences.size(); i++) { // The loop begin at 1, as the 0 stills injected.
+                        onServiceDeparture((ServiceReference) m_matchingReferences.get(i));
+                    }
+                }
+            }
+            // Else, do nothing.
+        }
+    }
+
+    public boolean isAggregate() {
+        return m_aggregate;
+    }
+
+    /**
+     * Set the optionality attribute of the current dependency.
+     * @param isOptional : the new optional attribute value.
+     */
+    public void setOptionality(boolean isOptional) {
+        if (m_tracker == null) { // Not started ...
+            m_optional = isOptional;
+        } else {
+            computeDependencyState();
+        }
+    }
+    
+    public boolean isOptional() {
+        return m_optional;
+    }
+
+    /**
+     * Return the used binding policy.
+     * @return the current binding policy.
+     */
+    public int getBindingPolicy() {
+        return m_policy;
+    }
+    
+    /**
+     * Set the binding policy.
+     * Not yet supported.
+     */
+    public void setBindingPolicy() {
+        throw new UnsupportedOperationException("Binding Policy change is not yet supported");
+        //TODO supporting dynamic policy change. 
+    }
+
+
+    public void setComparator(Comparator cmp) {
+        m_comparator = cmp;
+        // NOTE: the array will be sorted at the next get.
+    }
+
+    /**
+     * Set the bundle context used by this dependency.
+     * This operation is not supported if the tracker is already opened.
+     * @param bc : bundle context or service context to use
+     */
+    public void setBundleContext(BundleContext bc) {
+        if (m_tracker == null) { // Not started ...
+            m_context = bc;
+        } else {
+            throw new UnsupportedOperationException("Dynamic bundle (i.e. service) context change is not supported");
+        }
+    }
+
+
+    /**
+     * Get a service object for the given reference.
+     * @param ref : wanted service reference
+     * @return : the service object attached to the given reference
+     */
+    public Object getService(ServiceReference ref) {
+        return m_tracker.getService(ref);
+    }
+
+    /**
+     * Unget a used service reference.
+     * @param ref : reference to unget.
+     */
+    public void ungetService(ServiceReference ref) {
+        m_tracker.ungetService(ref);
+    }
+
+    /**
+     * Helper method parsing the comparator attribute and returning the
+     * comparator object. If the 'comparator' attribute is not set, this 
+     * method returns null. If the 'comparator' attribute is set to 'osgi',
+     * this method returns the normal OSGi comparator. In other case, it 
+     * tries to create an instance of the declared comparator class.
+     * @param dep : Element describing the dependency
+     * @param bc : bundle context (to load the comparator class)
+     * @return the comparator object, null if not set.
+     * @throws ConfigurationException the comparator class cannot be load or 
+     * the comparator cannot be instantiated correctly.
+     */
+    public static Comparator getComparator(Element dep, BundleContext bc) throws ConfigurationException {
+        Comparator cmp = null;
+        String comp = dep.getAttribute("comparator");
+        if (comp != null) {
+            if (comp.equalsIgnoreCase("osgi")) {
+                cmp = new ServiceReferenceRankingComparator();
+            } else {
+                try {
+                    Class cla = bc.getBundle().loadClass(comp);
+                    cmp = (Comparator) cla.newInstance();
+                } catch (ClassNotFoundException e) {
+                    throw new ConfigurationException("Cannot load a customized comparator : " + e.getMessage());
+                } catch (IllegalAccessException e) {
+                    throw new ConfigurationException("Cannot create a customized comparator : " + e.getMessage());
+                } catch (InstantiationException e) {
+                    throw new ConfigurationException("Cannot create a customized comparator : " + e.getMessage());
+                }
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Load the given specification class.
+     * @param specification : specification class name to load
+     * @param bc : bundle context
+     * @return : the class object for the given specification
+     * @throws ConfigurationException : the class cannot be loaded correctly.
+     */
+    public static Class loadSpecification(String specification, BundleContext bc) throws ConfigurationException {
+        Class spec = null;
+        try {
+            spec = bc.getBundle().loadClass(specification);
+        } catch (ClassNotFoundException e) {
+            throw new ConfigurationException("A required specification cannot be loaded : " + specification);
+        }
+        return spec;
+    }
+
+    /**
+     * Helper method parsing the binding policy.
+     * If the 'policy' attribute is not set in the dependency, the method
+     * returns the 'DYNAMIC BINDING POLICY'. Accepted policy values are :
+     * dynamic, dynamic-priority and static. 
+     * @param dep : Element describing the dependency 
+     * @return : the policy attached to this dependency
+     * @throws ConfigurationException : an unknown biding policy was described.
+     */
+    public static int getPolicy(Element dep) throws ConfigurationException {
+        String policy = dep.getAttribute("policy");
+        if (policy == null || policy.equalsIgnoreCase("dynamic")) {
+            return DYNAMIC_BINDING_POLICY;
+        } else if (policy.equalsIgnoreCase("dynamic-priority")) {
+            return DYNAMIC_PRIORITY_BINDING_POLICY;
+        } else if (policy.equalsIgnoreCase("static")) {
+            return STATIC_BINDING_POLICY;
+        } else {
+            throw new ConfigurationException("Binding policy unknown : " + policy);
+        }
+    }
+
+}

Modified: felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Tracker.java
URL: http://svn.apache.org/viewvc/felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Tracker.java?rev=629469&r1=629468&r2=629469&view=diff
==============================================================================
--- felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Tracker.java (original)
+++ felix/sandbox/clement/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Tracker.java Wed Feb 20 06:23:33 2008
@@ -326,8 +326,7 @@
             Iterator keys = tracked.keySet().iterator();
             for (int i = 0; i < length; i++) {
                 references[i] = (ServiceReference) keys.next();
-            }
-            // The resulting array is sorted by ranking.
+            }            
             return references;
         }
     }
@@ -350,6 +349,31 @@
                 references.add(keys.next());
             }
             // The resulting array is sorted by ranking.
+            return references;
+        }
+    }
+    
+    /**
+     * Return the list of references used by the tracker.
+     * A reference becomes used when the dependency has already
+     * call getService on this reference.
+     * @return : the list of used references.
+     */
+    public List/*<ServiceReference>*/getUsedServiceReferences() {
+        Tracked tracked = this.m_tracked; // use local var since we are not synchronized
+        if (tracked == null || tracked.size() == 0) { // if Tracker is not open or empty
+            return null;
+        }
+        synchronized (tracked) {
+            int length = tracked.size();
+            List references = new ArrayList();
+            Iterator keys = tracked.keySet().iterator();
+            for (int i = 0; i < length; i++) {
+                Object key = keys.next(); 
+                if (tracked.get(key) != null) {
+                    references.add(key);
+                }
+            }
             return references;
         }
     }



Mime
View raw message