You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cl...@apache.org on 2008/09/24 16:26:55 UTC

svn commit: r698589 [1/2] - in /felix/trunk/ipojo: core/src/main/java/org/apache/felix/ipojo/ core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ core/src/main/java/org/apache/felix/ipojo/util/ handler/eventadmin/src/main/resources/ handl...

Author: clement
Date: Wed Sep 24 07:26:55 2008
New Revision: 698589

URL: http://svn.apache.org/viewvc?rev=698589&view=rev
Log:
Improve javadoc of the instance creator
Fix several concurrency issues with the configuration admin (such as Felix-732)
Commit a test suite testing configuration admin support
Improve the documentation of XSD Schemas (external handlers)

Added:
    felix/trunk/ipojo/tests/core/configadmin/
    felix/trunk/ipojo/tests/core/configadmin/pom.xml
    felix/trunk/ipojo/tests/core/configadmin/src/
    felix/trunk/ipojo/tests/core/configadmin/src/main/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/component/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/component/ConfigurableFooProvider.java
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ConfigurationTestSuite.java
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForImmediate.java
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForServices.java
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceTestForImmediate.java
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceTestForService.java
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/service/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/service/CheckService.java
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/service/FooService.java
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configuration/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/util/
    felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/util/Utils.java
    felix/trunk/ipojo/tests/core/configadmin/src/main/resources/
    felix/trunk/ipojo/tests/core/configadmin/src/main/resources/metadata.xml
Modified:
    felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
    felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
    felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
    felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Callback.java
    felix/trunk/ipojo/handler/eventadmin/src/main/resources/event-admin.xsd
    felix/trunk/ipojo/handler/extender/src/main/resources/extender-pattern.xsd
    felix/trunk/ipojo/handler/jmx/src/main/resources/jmx.xsd
    felix/trunk/ipojo/handler/temporal/src/main/resources/temporal.xsd
    felix/trunk/ipojo/handler/whiteboard/src/main/resources/whiteboard-pattern.xsd
    felix/trunk/ipojo/tests/pom.xml

Modified: felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java?rev=698589&r1=698588&r2=698589&view=diff
==============================================================================
--- felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java (original)
+++ felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java Wed Sep 24 07:26:55 2008
@@ -30,43 +30,46 @@
 import org.osgi.framework.BundleContext;
 
 /**
- * An instance creator aims to create instances and to track their factories. It's allow to create instance from outside factories.
+ * The instance creator creates instances and tracks their factories. 
+ * It allows creating instances from external factories.
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class InstanceCreator implements FactoryStateListener {
 
     /**
-     * Logger to log messages if error occurs.
+     * The logger to log messages if errors occur.
      */
     private Logger m_logger;
 
     /**
-     * Configurations to create and maintains.
+     * The configurations to create and to maintain.
      */
     private List m_idle = new ArrayList();
 
     /**
-     * Map storing created instance. [AbstractFactory, List [ManagedInstance]]
+     * The map storing created instances.
+     * This map contains [AbstractFactory, List [ManagedInstance]] couples.
      */
     private Map m_attached = new HashMap();
 
     /**
-     * Abstract Factory list.
+     * The abstract factory list.
      */
     private List m_factories = new ArrayList();
 
     /**
-     * Constructor.
-     * @param context : iPOJO bundle context.
+     * Creates the instance creator.
+     * This object is generally a singleton.
+     * @param context the bundle context of the iPOJO bundle.
      */
     public InstanceCreator(BundleContext context) {
         m_logger = new Logger(context, "iPOJO Instance Creator");
     }
 
     /**
-     * Add an instance to manage.
-     * @param instance : instance configuration
-     * @param bundle : bundle id declaring the instance
+     * Adds an instance to manage.
+     * @param instance the instance configuration
+     * @param bundle the bundle id declaring the instance
      */
     synchronized void addInstance(Dictionary instance, long bundle) {
         ManagedInstance managed = new ManagedInstance(instance, bundle);
@@ -92,8 +95,8 @@
     }
 
     /**
-     * Dispose and stop to manage all instances declared by the given bundle.
-     * @param bundle : bundle.
+     * Disposes all instances declared by the given (leaving) bundle.
+     * @param bundle the bundle.
      */
     void removeInstancesFromBundle(long bundle) {
         // Disposes instance from attached instances
@@ -136,8 +139,8 @@
     }
 
     /**
-     * A new factory appears.
-     * @param factory : the new factory.
+     * This method is called when a factory appears.
+     * @param factory the new factory.
      */
     public synchronized void addFactory(IPojoFactory factory) {
         List createdInstances = new ArrayList(1);
@@ -167,8 +170,8 @@
     }
 
     /**
-     * A factory is leaving.
-     * @param factory : the leaving factory
+     * This method is called when a factory is leaving.
+     * @param factory the leaving factory
      */
     void removeFactory(IPojoFactory factory) {
         factory.removeFactoryStateListener(this);
@@ -178,8 +181,8 @@
     }
 
     /**
-     * The given factory becomes valid.
-     * @param factory : the factory becoming valid.
+     * This method is called when the given factory becomes valid.
+     * @param factory the factory becoming valid.
      */
     private void onValidation(IPojoFactory factory) {
         List toRemove = new ArrayList();
@@ -204,8 +207,8 @@
     }
 
     /**
-     * The given factory becomes invalid.
-     * @param factory : factory which becomes invalid.
+     * This method is called when the given factory becomes invalid.
+     * @param factory the factory becoming invalid.
      */
     private void onInvalidation(IPojoFactory factory) {
         List instances = (List) m_attached.remove(factory);
@@ -219,9 +222,9 @@
     }
 
     /**
-     * Factory state changed method.
-     * @param factory : factory.
-     * @param newState : new state.
+     * This method is called when the state of a factory changes.
+     * @param factory the factory.
+     * @param newState the new state.
      * @see org.apache.felix.ipojo.FactoryStateListener#stateChanged(org.apache.felix.ipojo.Factory, int)
      */
     public void stateChanged(Factory factory, int newState) {
@@ -233,33 +236,35 @@
     }
 
     /**
-     * This structure aims to manage a configuration. It stores all necessary information to create an instance and to track the factory.
+     * This structure aims to manage a configuration. 
+     * It stores all necessary information to create an instance 
+     * and to track the factory.
      */
     private class ManagedInstance {
         /**
-         * Configuration of the instance to create.
+         * The configuration of the instance to create.
          */
         private Dictionary m_configuration;
 
         /**
-         * Bundle which create the instance.
+         * The bundle which creates the instance.
          */
         private long m_bundleId;
 
         /**
-         * Factory used to create the instance.
+         * The factory used to create the instance.
          */
         private IPojoFactory m_factory;
 
         /**
-         * Created instance.
+         * The created instance.
          */
         private ComponentInstance m_instance;
 
         /**
-         * Constructor.
-         * @param conf : the configuration to create.
-         * @param bundle : the bundle in which the instance is declared.
+         * Creates a ManagedInstance.
+         * @param conf the configuration to create.
+         * @param bundle the bundle in which the instance is declared.
          */
         ManagedInstance(Dictionary conf, long bundle) {
             m_configuration = conf;
@@ -267,7 +272,7 @@
         }
 
         /**
-         * Return the used factory name.
+         * Returns the used factory.
          * @return the factory
          */
         IPojoFactory getFactory() {
@@ -275,18 +280,21 @@
         }
 
         /**
-         * Return the created instance.
-         * @return the instance (or null if no instance are created).
+         * Returns the created instance.
+         * @return the instance (or <code>null</code> if no instance are created).
          */
         ComponentInstance getInstance() {
             return m_instance;
         }
 
         /**
-         * Test if the given factory match with the factory required by this instance. A factory matches if its name or its class name is equals to
-         * the 'component' property of the instance. Then the acceptability of the configuration is checked.
-         * @param factory : the factory to confront against the current instance.
-         * @return true if the factory match.
+         * Checks if the given factory match with the factory 
+         * required by this instance. A factory matches if its 
+         * name or its class name is equals to the 'component' 
+         * property of the instance. Then the acceptability of 
+         * the configuration is checked.
+         * @param factory the factory to confront against the current instance.
+         * @return <code>true</code> if the factory matches.
          */
         public boolean match(IPojoFactory factory) {
             // Test factory name (and classname)
@@ -313,8 +321,8 @@
         }
 
         /**
-         * Create the instance by using the given factory.
-         * @param factory : the factory to use to create the instance. The factory must match.
+         * Creates the instance by using the given factory.
+         * @param factory the factory to use to create the instance. The factory must match.
          */
         public void create(IPojoFactory factory) {
             try {
@@ -333,7 +341,7 @@
         }
 
         /**
-         * Dispose the current instance.
+         * Disposes the current instance if not <code>null</code>.
          */
         public void dispose() {
             if (m_instance != null) {

Modified: felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java?rev=698589&r1=698588&r2=698589&view=diff
==============================================================================
--- felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java (original)
+++ felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceManager.java Wed Sep 24 07:26:55 2008
@@ -518,12 +518,8 @@
         }
         return m_pojoObjects.toArray(new Object[m_pojoObjects.size()]);
     }
-
-    /**
-     * Create an instance of the component. This method need to be called one time only for singleton provided service.
-     * @return a new instance
-     */
-    public Object createPojoObject() {
+    
+    private Object createObject() {
         if (m_clazz == null) {
             load();
         }
@@ -662,6 +658,16 @@
                 return null;
             }
         }
+        return instance;
+    }
+
+    /**
+     * Create an instance of the component. 
+     * This method need to be called one time only for singleton provided service.
+     * @return a new instance
+     */
+    public Object createPojoObject() {
+        Object instance = createObject();
 
         // Add the new instance in the instance list.
         synchronized (this) {
@@ -684,17 +690,27 @@
      */
     public Object getPojoObject() {
         Object pojo = null;
+        boolean newPOJO = false;
         synchronized (this) {
             if (m_pojoObjects != null) {
                 pojo = m_pojoObjects.get(0); // Stack confinement
+            } else {
+                pojo = createObject();  // Stack confinement
+                if (m_pojoObjects == null) {
+                    m_pojoObjects = new ArrayList(1);
+                }
+                m_pojoObjects.add(pojo);
+                newPOJO = true;
             }
         }
         
-        if (pojo == null) {
-            return createPojoObject(); // This method must be called without the lock.
-        } else {
-            return pojo;
-        }
+        // Call createInstance on Handlers :
+        for (int i = 0; newPOJO && i < m_handlers.length; i++) {
+            ((PrimitiveHandler) m_handlers[i].getHandler()).onCreation(pojo);
+        } 
+        //NOTE this method allows returning a POJO object before calling the onCreation on handler.
+
+        return pojo;
     }
 
     /**

Modified: felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java?rev=698589&r1=698588&r2=698589&view=diff
==============================================================================
--- felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java (original)
+++ felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java Wed Sep 24 07:26:55 2008
@@ -321,7 +321,8 @@
      * @param configuration : the new configuration
      * @see org.apache.felix.ipojo.Handler#reconfigure(java.util.Dictionary)
      */
-    public synchronized void reconfigure(Dictionary configuration) {   
+    public synchronized void reconfigure(Dictionary configuration) {  
+        warn(getInstanceManager().getInstanceName() + " is reconfiguring the properties : " + configuration);
         Properties props = reconfigureProperties(configuration);
         propagate(props, m_propagatedFromInstance);
         m_propagatedFromInstance = props;
@@ -348,12 +349,16 @@
                             m_configurableProperties[i].setValue(value);
                             getInstanceManager().onSet(null, m_configurableProperties[i].getField(), m_configurableProperties[i].getValue()); // Notify other handler of the field value change.
                             if (m_configurableProperties[i].hasMethod()) {
-                                m_configurableProperties[i].invoke(null); // Call on all created pojo objects.
+                                if (getInstanceManager().getPojoObjects() != null) {
+                                    m_configurableProperties[i].invoke(null); // Call on all created pojo objects.
+                                }
                             }
                         }
                     } else if (m_configurableProperties[i].hasMethod()) { // Method but no field
                         m_configurableProperties[i].setValue(value);
-                        m_configurableProperties[i].invoke(null); // Call on all created pojo objects.
+                        if (getInstanceManager().getPojoObjects() != null) {
+                            m_configurableProperties[i].invoke(null); // Call on all created pojo objects.
+                        }
                     }
                     found = true;
                     break;

Modified: felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Callback.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Callback.java?rev=698589&r1=698588&r2=698589&view=diff
==============================================================================
--- felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Callback.java (original)
+++ felix/trunk/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Callback.java Wed Sep 24 07:26:55 2008
@@ -205,7 +205,8 @@
             // - if instances already exists : call on each instances
             // - if no instance exists : create an instance
             if (m_manager.getPojoObjects() == null) {
-                return m_methodObj.invoke(m_manager.getPojoObject(), arg);
+                Object r = m_methodObj.invoke(m_manager.getPojoObject(), arg);
+                return r;
             } else {
                 Object newObject = null;
                 for (int i = 0; i < m_manager.getPojoObjects().length; i++) {

Modified: felix/trunk/ipojo/handler/eventadmin/src/main/resources/event-admin.xsd
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/eventadmin/src/main/resources/event-admin.xsd?rev=698589&r1=698588&r2=698589&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/eventadmin/src/main/resources/event-admin.xsd (original)
+++ felix/trunk/ipojo/handler/eventadmin/src/main/resources/event-admin.xsd Wed Sep 24 07:26:55 2008
@@ -22,20 +22,66 @@
 	elementFormDefault="qualified">	
 
     <xs:complexType name="PublisherType">
-    	<xs:attribute name="name" type="xs:string" use="required"></xs:attribute>
-    	<xs:attribute name="field" type="xs:string" use="required"></xs:attribute>
-    	<xs:attribute name="topics" type="xs:string" use="optional"></xs:attribute>
-    	<xs:attribute name="synchronous" type="xs:boolean" use="optional"></xs:attribute>
-    	<xs:attribute name="data-key" type="xs:string" use="optional"></xs:attribute>
+        <xs:annotation>
+        	<xs:documentation>Description of an event publisher.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="name" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The name of the event publisher, acting as a unique identifier.
+The name of the POJO's field that will be used to send events. The field is initialized at component instantiation time. The type of the field must be "org.apache.felix.ipojo.handlers.event.publisher.Publisher".</xs:documentation>
+        	</xs:annotation></xs:attribute>
+    	<xs:attribute name="field" type="xs:string" use="required">
+    		<xs:annotation>
+    			<xs:documentation>The name of the POJO field associated to this event publisher.
+Despite it creates a dependency between the component code and the handler, this system allows hiding the whole complexity of event sending.</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="topics" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The comma-separated-list of the topics on which events will be sent. All subscribers that are listening to one of these topics will receive the events.</xs:documentation></xs:annotation></xs:attribute>
+    	<xs:attribute name="synchronous" type="xs:boolean" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>Determines if event sending is synchronous or not. By default, events are sent asynchronously, but you can specify there the desired behaviour of the Publisher.
+The default value of this attribute is "false".</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="data-key" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The data key is used when you want to send data events. This attribute's value is the key, in the event's dictionary, in which sent data are stored. When you use the sendData method of the Publisher, the given object is placed in the event dictionary, associated with the specified data-key.
+The default value of this attribute is user.data.</xs:documentation></xs:annotation></xs:attribute>
     </xs:complexType>
     
     <xs:complexType name="SubscriberType">
-    	<xs:attribute name="name" type="xs:string" use="required"></xs:attribute>
-    	<xs:attribute name="callback" type="xs:string" use="required"></xs:attribute>
-    	<xs:attribute name="topics" type="xs:string" use="optional"></xs:attribute>
-    	<xs:attribute name="filter" type="xs:string" use="optional"></xs:attribute>
-    	<xs:attribute name="data-key" type="xs:string" use="optional"></xs:attribute>
-    	<xs:attribute name="data-type" type="xs:string" use="optional"></xs:attribute>
+        <xs:annotation>
+        	<xs:documentation>Description of an event subscriber.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="name" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The name of the event subscriber, acting as a unique identifier.</xs:documentation></xs:annotation></xs:attribute>
+    	<xs:attribute name="callback" type="xs:string" use="required">
+    		<xs:annotation>
+    			<xs:documentation>The name of the POJO's method that will be called each time an event is received.
+This method takes only one parameter, of typeorg.osgi.service.event.Eventby default, but this type can be overridden by defining the data-key and/or the data-type attributes.</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="topics" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The comma-separated-list of the topics that the handler will listen to. Each event sent on a topic present in this list will be sent to the specified callback method.</xs:documentation></xs:annotation></xs:attribute>
+    	<xs:attribute name="filter" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The event filter is used to filter incoming events before sending them to the callback.
+The syntax of this field is described in the OSGi EventAdmin Specification. If you don't specify a filter, all events sent on the listened topics will be considered.</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="data-key" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The data key is used when you want to receive data events. This attribute's value is the key corresponding to the received data in the event's dictionary.
+If you use this attribute, the parameter passed to the callback method is the the value associated to this key, not the whole event.
+This attribute is generally used with the data-typeattribute to specify the received object type.
+If an event is received and it does not contain such a key, it is ignored (with a warning message).</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="data-type" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>This attribute is associated to the data-key attribute. It specifies the type of objects (java.lang.Object by default) that the callback expects.
+It is used to determine the unique callback method (in case of multiple methods with the same name) and to check type compliance at event reception.
+Data events that are not corresponding to the specified type will be ignored (with a warning message).</xs:documentation>
+    		</xs:annotation></xs:attribute>
     </xs:complexType>
     
     <xs:element name="publisher" type="PublisherType"></xs:element>

Modified: felix/trunk/ipojo/handler/extender/src/main/resources/extender-pattern.xsd
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/extender/src/main/resources/extender-pattern.xsd?rev=698589&r1=698588&r2=698589&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/extender/src/main/resources/extender-pattern.xsd (original)
+++ felix/trunk/ipojo/handler/extender/src/main/resources/extender-pattern.xsd Wed Sep 24 07:26:55 2008
@@ -22,8 +22,21 @@
 	elementFormDefault="qualified">
 	<xs:element name="extender" type="ExtenderType"></xs:element>
 	<xs:complexType name="ExtenderType">
-		<xs:attribute name="onArrival" type="xs:string" use="required"></xs:attribute>
-		<xs:attribute name="onDeparture" type="xs:string" use="required"></xs:attribute>
-		<xs:attribute name="extension" type="xs:string" use="required"></xs:attribute>
+        <xs:annotation>
+        	<xs:documentation>Description of the extender pattern configuration.
+The extender tracks extensions. The particularity of this architecture-style is that extensions are packaged in different bundles. An extension is detected by analyzing the bundle. The mark is currently a header in the bundle manifest. At each time a matching bundle appears or disappears, a callback is invoked. </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="onArrival" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>Declaring the method to invoke when a matching bundle arrives</xs:documentation>
+        	</xs:annotation></xs:attribute>
+		<xs:attribute name="onDeparture" type="xs:string" use="required">
+			<xs:annotation>
+				<xs:documentation>Declaring the method to invoke when a matching bundle leaves</xs:documentation>
+			</xs:annotation></xs:attribute>
+		<xs:attribute name="extension" type="xs:string" use="required">
+			<xs:annotation>
+				<xs:documentation>Declaring the looked manifest header.</xs:documentation>
+			</xs:annotation></xs:attribute>
 	</xs:complexType>	
 </xs:schema>
\ No newline at end of file

Modified: felix/trunk/ipojo/handler/jmx/src/main/resources/jmx.xsd
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/jmx/src/main/resources/jmx.xsd?rev=698589&r1=698588&r2=698589&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/jmx/src/main/resources/jmx.xsd (original)
+++ felix/trunk/ipojo/handler/jmx/src/main/resources/jmx.xsd Wed Sep 24 07:26:55 2008
@@ -24,37 +24,154 @@
 
 	<xs:complexType name="JMXType">
 
+		<xs:annotation>
+			<xs:documentation>
+				Description of a JMX managed component.
+			</xs:documentation>
+		</xs:annotation>
 		<xs:choice minOccurs="0" maxOccurs="unbounded">
-			<xs:element name="method" type="JMXMethod"></xs:element>
-			<xs:element name="property" type="JMXProperty"></xs:element>
+			<xs:element name="method" type="JMXMethod">
+				<xs:annotation>
+					<xs:documentation>
+						The list of methods to expose.
+					</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="property" type="JMXProperty">
+				<xs:annotation>
+					<xs:documentation>
+						The list of attributes to expose.
+					</xs:documentation>
+				</xs:annotation>
+			</xs:element>
 		</xs:choice>
 		<xs:attribute name="usesMOSGi" type="xs:boolean"
 			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Determines if the component must be register on the
+					MOSGi MBean server or not.
+				</xs:documentation>
+			</xs:annotation>
 		</xs:attribute>
 		<xs:attribute name="objectName" type="xs:string"
 			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					The complete object name of the managed component.
+					The syntax of this attribute must be compliant with
+					the ObjectName syntax, detailed in the JMX
+					specification. If neither domain nor name attributes
+					are specified, the default value is determined by
+					the package, the type and the instance name of the
+					component. This attribute overrides the domain and
+					name attributes.
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="domain" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					The domain of the managed object (i.e., the left
+					part of the object name). This attribute must be
+					compliant with the domain syntax, as described in
+					the JMX specification.
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="name" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					The name property of the managed object. The value
+					of this attribute must comply with the ObjectName
+					value syntax, as described in the JMX specification.
+				</xs:documentation>
+			</xs:annotation>
 		</xs:attribute>
-		<xs:attribute name="domain" type="xs:string" use="optional"></xs:attribute>
-		<xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
 
+		<xs:attribute name="preRegister" type="xs:string"
+			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Specifies method to carry out operations before
+					beeing registered from the MBean server. The
+					signature of the specified method must be :
+					"ObjectName preRegister(MBeanServer server,
+					ObjectName name) throws Exception".
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="postRegister" type="xs:string"
+			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Specifies method to carry out operations after
+					beeing registered from the MBean server. The
+					signature of the specified method must be : "void
+					postRegister(Boolean registrationDone)".
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="preDeregister" type="xs:string"
+			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Specifies method to carry out operations before
+					beeing unregistered from the MBean server. The
+					signature of the specified method must be : "void
+					preDeregister() throws Exception".
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="postDeregister" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Specifies method to carry out operations after
+					beeing unregistered from the MBean server. The
+					signature of the specified method must be : 
+					"void postDeregister()".</xs:documentation>
+			</xs:annotation></xs:attribute>
 	</xs:complexType>
 
 	<xs:complexType name="JMXProperty">
-		<xs:attribute name="field" type="xs:string" use="required"></xs:attribute>
-		<xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
+        <xs:annotation>
+        	<xs:documentation>Description of an attribute to expose.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="field" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The name of the component's field to expose.</xs:documentation></xs:annotation></xs:attribute>
+		<xs:attribute name="name" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>The name of the property as it will appear in JMX. If unspecified, the default value is the name of the exposed field.</xs:documentation></xs:annotation></xs:attribute>
 		<xs:attribute name="rights" use="optional">
-			<xs:simpleType>
-				<xs:restriction base="xs:string">
+            <xs:annotation>
+            	<xs:documentation>Specify the access permission of the exposed field.</xs:documentation>
+            </xs:annotation>
+            <xs:simpleType>
+                <xs:annotation>
+                	<xs:documentation>Access permission of an exposed field. Accepted values are "r" (read-only access, the default value) and "w" (read and write access).</xs:documentation>
+                </xs:annotation>
+                <xs:restriction base="xs:string">
 					<xs:enumeration value="r"></xs:enumeration>
 					<xs:enumeration value="w"></xs:enumeration>
 				</xs:restriction>
 			</xs:simpleType>
 		</xs:attribute>
-		<xs:attribute name="notification" type="xs:boolean" use="optional"></xs:attribute>
+		<xs:attribute name="notification" type="xs:boolean" use="optional">
+			<xs:annotation>
+				<xs:documentation>Enable or disable attribute change notification sending for this property. If set to &quot;true&quot;, a notification is sent each time the value of the field changes.</xs:documentation></xs:annotation></xs:attribute>
 	</xs:complexType>
 
 	<xs:complexType name="JMXMethod">
-		<xs:attribute name="name" type="xs:string" use="required"></xs:attribute>
-		<xs:attribute name="description" type="xs:string" use="optional"></xs:attribute>
+        <xs:annotation>
+        	<xs:documentation>Description of a method to expose.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="name" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The name of the method to expose. If multiple methods have the same name, all of them are exposed.</xs:documentation>
+        	</xs:annotation></xs:attribute>
+		<xs:attribute name="description" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>The description of the exposed method, as it will appear in JMX.</xs:documentation></xs:annotation></xs:attribute>
 	</xs:complexType>
 </xs:schema>
\ No newline at end of file

Modified: felix/trunk/ipojo/handler/temporal/src/main/resources/temporal.xsd
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/temporal/src/main/resources/temporal.xsd?rev=698589&r1=698588&r2=698589&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/temporal/src/main/resources/temporal.xsd (original)
+++ felix/trunk/ipojo/handler/temporal/src/main/resources/temporal.xsd Wed Sep 24 07:26:55 2008
@@ -24,15 +24,23 @@
 
 	<xs:complexType name="TemporalServiceDependencyType">
 
-		<xs:attribute name="field" type="xs:string" use="required"></xs:attribute>
-		<xs:attribute name="filter" type="xs:string" use="optional"></xs:attribute>
+        <xs:annotation>
+        	<xs:documentation>Description of a temporal dependency.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="field" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The implementation field supporting the dependency.</xs:documentation>
+        	</xs:annotation></xs:attribute>
+		<xs:attribute name="filter" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>Filter use to discover matching filter.</xs:documentation></xs:annotation></xs:attribute>
 		<xs:attribute name="timeout" type="xs:int" use="optional">
 			<xs:annotation>
-				<xs:documentation>Specifies the timeout after which the onTimeout policy is executed.
The value is the time in ms to wait. -1 is used to indicate an infinite wait. </xs:documentation>
+				<xs:documentation>Specifies the timeout after which the onTimeout policy is executed. The value is the time in ms to wait. -1 is used to indicate an infinite wait.</xs:documentation>
 			</xs:annotation></xs:attribute>
 		<xs:attribute name="onTimeout" use="optional" type="xs:string">
             <xs:annotation>
-            	<xs:documentation>Specifies the onTimeout policy. This determines the object to inject when the service stills unavailable when the timeout expires.
Several values are supported:
- 'nullable' means that a Nullable object will be injected
- 'empty-array' injects an empty array (only for aggregate dependency)
- 'null' injects Null
- any other value are interpreted as the default implementation class to use.

If the onTimetout attribute is not specified, a RuntimeException is thrown when the timeout is reached.</xs:documentation>
+            	<xs:documentation>Specifies the onTimeout policy. This determines the object to inject when the service stills unavailable when the timeout expires. Several values are supported: 'nullable' means that a Nullable object will be injected, 'empty-array' injects an empty array (only for aggregate dependency), 'null' injects Null, any other value are interpreted as the default implementation class to use. If the onTimetout attribute is not specified, a RuntimeException is thrown when the timeout is reached.</xs:documentation>
             </xs:annotation>
 		</xs:attribute>
 	</xs:complexType>

Modified: felix/trunk/ipojo/handler/whiteboard/src/main/resources/whiteboard-pattern.xsd
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/handler/whiteboard/src/main/resources/whiteboard-pattern.xsd?rev=698589&r1=698588&r2=698589&view=diff
==============================================================================
--- felix/trunk/ipojo/handler/whiteboard/src/main/resources/whiteboard-pattern.xsd (original)
+++ felix/trunk/ipojo/handler/whiteboard/src/main/resources/whiteboard-pattern.xsd Wed Sep 24 07:26:55 2008
@@ -22,9 +22,24 @@
 	elementFormDefault="qualified">
 	<xs:element name="wbp" type="WBPType"></xs:element>
 	<xs:complexType name="WBPType">
-		<xs:attribute name="onArrival" type="xs:string" use="required"></xs:attribute>
-		<xs:attribute name="onDeparture" type="xs:string" use="required"></xs:attribute>
-		<xs:attribute name="onModification" type="xs:string" use="optional"></xs:attribute>
-		<xs:attribute name="filter" type="xs:string" use="required"></xs:attribute>
+        <xs:annotation>
+        	<xs:documentation>Description of the white-board architecture.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="onArrival" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>Declaring the method to invoke when a matching service arrives.</xs:documentation>
+        	</xs:annotation></xs:attribute>
+		<xs:attribute name="onDeparture" type="xs:string" use="required">
+			<xs:annotation>
+				<xs:documentation>Declaring the method to invoke when a matching service leaves.</xs:documentation>
+			</xs:annotation></xs:attribute>
+		<xs:attribute name="onModification" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>Method called when an injected service reference is modified but stills valid against the filter.</xs:documentation>
+			</xs:annotation></xs:attribute>
+		<xs:attribute name="filter" type="xs:string" use="required">
+			<xs:annotation>
+				<xs:documentation>Filter use to discover matching filter.</xs:documentation>
+			</xs:annotation></xs:attribute>
 	</xs:complexType>	
 </xs:schema>
\ No newline at end of file

Added: felix/trunk/ipojo/tests/core/configadmin/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/tests/core/configadmin/pom.xml?rev=698589&view=auto
==============================================================================
--- felix/trunk/ipojo/tests/core/configadmin/pom.xml (added)
+++ felix/trunk/ipojo/tests/core/configadmin/pom.xml Wed Sep 24 07:26:55 2008
@@ -0,0 +1,101 @@
+<!--
+	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.
+-->
+<project>
+	<modelVersion>4.0.0</modelVersion>
+	<packaging>bundle</packaging>
+	<name>iPOJO Configuration Admin Management Test Suite</name>
+	<artifactId>tests.core.configadmin</artifactId>
+	<groupId>ipojo.tests</groupId>
+	<version>0.9.0-SNAPSHOT</version>
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.apache.felix.ipojo</artifactId>
+			<version>0.9.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.apache.felix.ipojo.metadata</artifactId>
+			<version>0.9.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.osgi.core</artifactId>
+			<version>1.0.0</version>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>3.8.1</version>
+		</dependency>
+		<dependency>
+			<groupId>ipojo.examples</groupId>
+			<artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>
+			<version>0.9.0-SNAPSHOT</version>
+		</dependency>
+	</dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<version>1.4.2</version>
+				<extensions>true</extensions>
+				<configuration>
+					<instructions>
+						<Export-Package>
+							org.apache.felix.ipojo.test.scenarios.configadmin.service
+						</Export-Package>
+						<Bundle-SymbolicName>
+							${pom.artifactId}
+						</Bundle-SymbolicName>
+						<Private-Package>
+							org.apache.felix.ipojo.test*
+						</Private-Package>
+						<Test-Suite>
+							org.apache.felix.ipojo.test.scenarios.configadmin.ConfigurationTestSuite						</Test-Suite>
+					</instructions>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-ipojo-plugin</artifactId>
+				<version>0.9.0-SNAPSHOT</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>ipojo-bundle</goal>
+						</goals>
+						<configuration>
+							<ignoreAnnotations>true</ignoreAnnotations>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>1.4</source>
+					<target>1.4</target>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>

Added: felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/component/ConfigurableFooProvider.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/component/ConfigurableFooProvider.java?rev=698589&view=auto
==============================================================================
--- felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/component/ConfigurableFooProvider.java (added)
+++ felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/component/ConfigurableFooProvider.java Wed Sep 24 07:26:55 2008
@@ -0,0 +1,53 @@
+package org.apache.felix.ipojo.test.scenarios.component;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.test.scenarios.configadmin.service.FooService;
+
+public class ConfigurableFooProvider implements FooService {
+    
+    private String message; // Configurable property
+    private int invokeCount = 0;
+    
+    public void setMessage(String message) {
+        System.out.println("Set message to " + message);
+        this.message = message;
+        invokeCount++;
+    }
+
+    public boolean foo() {
+        return true;
+    }
+
+    public Properties fooProps() {
+        Properties props = new Properties();
+        if (message == null) {
+            props.put("message", "NULL");
+        } else {
+            props.put("message", message);
+        }
+        props.put("count", new Integer(invokeCount));
+        return props;
+    }
+
+    public boolean getBoolean() {
+        return false;
+    }
+
+    public double getDouble() {
+        return invokeCount;
+    }
+
+    public int getInt() {
+        return invokeCount;
+    }
+
+    public long getLong() {
+        return invokeCount;
+    }
+
+    public Boolean getObject() {
+        return null;
+    }
+
+}

Added: felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ConfigurationTestSuite.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ConfigurationTestSuite.java?rev=698589&view=auto
==============================================================================
--- felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ConfigurationTestSuite.java (added)
+++ felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ConfigurationTestSuite.java Wed Sep 24 07:26:55 2008
@@ -0,0 +1,37 @@
+/* 
+ * 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.test.scenarios.configadmin;
+
+import junit.framework.Test;
+
+import org.apache.felix.ipojo.junit4osgi.OSGiTestSuite;
+import org.osgi.framework.BundleContext;
+
+public class ConfigurationTestSuite {
+
+	public static Test suite(BundleContext bc) {
+		OSGiTestSuite ots = new OSGiTestSuite("Configuration Admin Test Suite", bc);
+		ots.addTestSuite(ManagedServiceFactoryTestForServices.class);
+	      ots.addTestSuite(ManagedServiceFactoryTestForImmediate.class);
+	      ots.addTestSuite(ManagedServiceTestForImmediate.class);
+	      ots.addTestSuite(ManagedServiceTestForService.class);
+		return ots;
+	}
+
+}

Added: felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForImmediate.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForImmediate.java?rev=698589&view=auto
==============================================================================
--- felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForImmediate.java (added)
+++ felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForImmediate.java Wed Sep 24 07:26:55 2008
@@ -0,0 +1,337 @@
+package org.apache.felix.ipojo.test.scenarios.configadmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
+import org.apache.felix.ipojo.test.scenarios.configadmin.service.FooService;
+import org.apache.felix.ipojo.test.scenarios.util.Utils;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class ManagedServiceFactoryTestForImmediate extends OSGiTestCase {
+    
+    private ComponentFactory factory;
+    private ConfigurationAdmin admin;
+    
+    public void setUp() {
+        factory = (ComponentFactory) Utils.getFactoryByName(context, "CA-ImmConfigurableProvider");
+        admin = (ConfigurationAdmin) Utils.getServiceObject(context, ConfigurationAdmin.class.getName(), null);
+        assertNotNull("Check configuration admin availability", admin);
+        try {
+            Configuration[] configurations = admin.listConfigurations("(service.factoryPid=CA-ImmConfigurableProvider)");
+            for (int i = 0; configurations != null && i < configurations.length; i++) {
+                configurations[i].delete();
+            }
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (InvalidSyntaxException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+    
+    public void tearDown() {
+        try {
+            Configuration[] configurations = admin.listConfigurations("(service.factoryPid=CA-ImmConfigurableProvider)");
+            for (int i = 0; configurations != null && i < configurations.length; i++) {
+                configurations[i].delete();
+            }
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (InvalidSyntaxException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        admin = null;
+
+        
+    }
+    
+    public void testCreationAndReconfiguration() {
+        Configuration configuration = null;
+        try {
+            configuration = admin.createFactoryConfiguration("CA-ImmConfigurableProvider", null);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        Dictionary props = configuration.getProperties();
+        if(props == null) {
+            props = new Properties();
+        }
+        props.put("message", "message");
+        
+        try {
+            configuration.update(props);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        
+        String pid = configuration.getPid();
+        System.out.println("PID : " + pid);
+        
+        //  The instance should be created, wait for the architecture service
+        Utils.waitForService(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        Architecture architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        FooService fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        Properties p = fs.fooProps();
+        String mes = p.getProperty("message");
+        int count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message", mes);
+        assertEquals("Assert count", 1, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        props.put("message", "message2");
+        try {
+            configuration.update(props);
+            // Update the configuration ...
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        p = fs.fooProps();
+        mes = p.getProperty("message");
+        count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message2", mes);
+        assertEquals("Assert count", 2, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        try {
+            configuration.delete();
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        ServiceReference ref = Utils.getServiceReference(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        assertNull("Check unavailability", ref);
+    }
+    
+    public void testCreationAndReconfiguration2() {
+        //The reconfiguration happens before the service invocation
+        Configuration configuration = null;
+        try {
+            configuration = admin.createFactoryConfiguration("CA-ImmConfigurableProvider", null);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        Dictionary props = configuration.getProperties();
+        if(props == null) {
+            props = new Properties();
+        }
+        props.put("message", "message");
+        
+        try {
+            configuration.update(props);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        
+        String pid = configuration.getPid();
+        System.out.println("PID : " + pid);
+        
+        //  The instance should be created, wait for the architecture service
+        Utils.waitForService(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        Architecture architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        props.put("message", "message2");
+        try {
+            configuration.update(props);
+            // Update the configuration ...
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check object -2", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        //Invoke
+        FooService fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        Properties p = fs.fooProps();
+        String mes = p.getProperty("message");
+        int count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message2", mes);
+        assertEquals("Assert count", 2, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+                
+        try {
+            configuration.delete();
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        ServiceReference ref = Utils.getServiceReference(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        assertNull("Check unavailability", ref);
+    }
+    
+    public void testDelayedCreationAndReconfiguration() {
+        factory.stop();
+        Configuration configuration = null;
+        try {
+            configuration = admin.createFactoryConfiguration("CA-ImmConfigurableProvider", null);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        Dictionary props = configuration.getProperties();
+        if(props == null) {
+            props = new Properties();
+        }
+        props.put("message", "message");
+        
+        try {
+            configuration.update(props);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        
+        String pid = configuration.getPid();
+        System.out.println("PID : " + pid);
+        
+        assertNull("check no instance", Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")"));
+        
+        factory.start();
+        
+        
+        //  The instance should be created, wait for the architecture service
+        Utils.waitForService(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        Architecture architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        FooService fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        Properties p = fs.fooProps();
+        String mes = p.getProperty("message");
+        int count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message", mes);
+        assertEquals("Assert count", 1, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        props.put("message", "message2");
+        try {
+            configuration.update(props);
+            // Update the configuration ...
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        p = fs.fooProps();
+        mes = p.getProperty("message");
+        count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message2", mes);
+        //assertEquals("Assert count", 2, count);
+        // This test was removed as the result can be 3. 
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        try {
+            configuration.delete();
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        ServiceReference ref = Utils.getServiceReference(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        assertNull("Check unavailability", ref);
+    }
+    
+    public void testDelayedCreationAndReconfiguration2() {
+        factory.stop();
+        //The reconfiguration happens before the service invocation
+        Configuration configuration = null;
+        try {
+            configuration = admin.createFactoryConfiguration("CA-ImmConfigurableProvider", null);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        Dictionary props = configuration.getProperties();
+        if(props == null) {
+            props = new Properties();
+        }
+        props.put("message", "message");
+        
+        try {
+            configuration.update(props);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        
+        String pid = configuration.getPid();
+        System.out.println("PID : " + pid);
+        
+        assertNull("check no instance", Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")"));
+        
+        factory.start();
+        
+        
+        //  The instance should be created, wait for the architecture service
+        Utils.waitForService(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        Architecture architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        props.put("message", "message2");
+        try {
+            configuration.update(props);
+            // Update the configuration ...
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check object -1", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        //Invoke
+        FooService fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        Properties p = fs.fooProps();
+        String mes = p.getProperty("message");
+        int count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message2", mes);
+        //assertEquals("Assert count", 2, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+                
+        try {
+            configuration.delete();
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        ServiceReference ref = Utils.getServiceReference(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        assertNull("Check unavailability", ref);
+    }
+    
+    
+
+}

Added: felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForServices.java
URL: http://svn.apache.org/viewvc/felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForServices.java?rev=698589&view=auto
==============================================================================
--- felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForServices.java (added)
+++ felix/trunk/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForServices.java Wed Sep 24 07:26:55 2008
@@ -0,0 +1,340 @@
+package org.apache.felix.ipojo.test.scenarios.configadmin;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
+import org.apache.felix.ipojo.test.scenarios.configadmin.service.FooService;
+import org.apache.felix.ipojo.test.scenarios.util.Utils;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class ManagedServiceFactoryTestForServices extends OSGiTestCase {
+    
+    private ComponentFactory factory;
+    private ConfigurationAdmin admin;
+    
+    public void setUp() {
+        factory = (ComponentFactory) Utils.getFactoryByName(context, "CA-ConfigurableProvider");
+        admin = (ConfigurationAdmin) Utils.getServiceObject(context, ConfigurationAdmin.class.getName(), null);
+        assertNotNull("Check configuration admin availability", admin);
+        try {
+            Configuration[] configurations = admin.listConfigurations("(service.factoryPid=CA-ConfigurableProvider)");
+            for (int i = 0; configurations != null && i < configurations.length; i++) {
+                configurations[i].delete();
+            }
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (InvalidSyntaxException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+    
+    public void tearDown() {
+        try {
+            Configuration[] configurations = admin.listConfigurations("(service.factoryPid=CA-ConfigurableProvider)");
+            for (int i = 0; configurations != null && i < configurations.length; i++) {
+                configurations[i].delete();
+            }
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (InvalidSyntaxException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        admin = null;
+
+        
+    }
+    
+    public void testCreationAndReconfiguration() {
+        Configuration configuration = null;
+        try {
+            configuration = admin.createFactoryConfiguration("CA-ConfigurableProvider", null);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        Dictionary props = configuration.getProperties();
+        if(props == null) {
+            props = new Properties();
+        }
+        props.put("message", "message");
+        
+        try {
+            configuration.update(props);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        
+        String pid = configuration.getPid();
+        System.out.println("PID : " + pid);
+        
+        //  The instance should be created, wait for the architecture service
+        Utils.waitForService(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        Architecture architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check no object", 0, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        FooService fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        Properties p = fs.fooProps();
+        String mes = p.getProperty("message");
+        int count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message", mes);
+        assertEquals("Assert count", 1, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        props.put("message", "message2");
+        try {
+            configuration.update(props);
+            // Update the configuration ...
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        p = fs.fooProps();
+        mes = p.getProperty("message");
+        count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message2", mes);
+        assertEquals("Assert count", 2, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        try {
+            configuration.delete();
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        ServiceReference ref = Utils.getServiceReference(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        assertNull("Check unavailability", ref);
+    }
+    
+    public void testCreationAndReconfiguration2() {
+        //The reconfiguration happens before the service invocation
+        Configuration configuration = null;
+        try {
+            configuration = admin.createFactoryConfiguration("CA-ConfigurableProvider", null);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        Dictionary props = configuration.getProperties();
+        if(props == null) {
+            props = new Properties();
+        }
+        props.put("message", "message");
+        
+        try {
+            configuration.update(props);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        
+        String pid = configuration.getPid();
+        System.out.println("PID : " + pid);
+        
+        //  The instance should be created, wait for the architecture service
+        Utils.waitForService(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        Architecture architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check no object", 0, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        props.put("message", "message2");
+        try {
+            configuration.update(props);
+            // Update the configuration ...
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check no object -2", 0, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        //Invoke
+        FooService fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        Properties p = fs.fooProps();
+        String mes = p.getProperty("message");
+        int count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message2", mes);
+        assertEquals("Assert count", 1, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+                
+        try {
+            configuration.delete();
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        ServiceReference ref = Utils.getServiceReference(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        assertNull("Check unavailability", ref);
+    }
+    
+    public void testDelayedCreationAndReconfiguration() {
+        factory.stop();
+        Configuration configuration = null;
+        try {
+            configuration = admin.createFactoryConfiguration("CA-ConfigurableProvider", null);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        Dictionary props = configuration.getProperties();
+        if(props == null) {
+            props = new Properties();
+        }
+        props.put("message", "message");
+        
+        try {
+            configuration.update(props);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        
+        String pid = configuration.getPid();
+        System.out.println("PID : " + pid);
+        
+        assertNull("check no instance", Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")"));
+        
+        factory.start();
+        
+        
+        //  The instance should be created, wait for the architecture service
+        Utils.waitForService(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        Architecture architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check no object", 0, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        FooService fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        Properties p = fs.fooProps();
+        String mes = p.getProperty("message");
+        int count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message", mes);
+        assertEquals("Assert count", 1, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        System.out.println("===");
+        
+        props.put("message", "message2");
+        try {
+            configuration.update(props);
+            // Update the configuration ...
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        System.out.println("===");
+        
+        fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        p = fs.fooProps();
+        mes = p.getProperty("message");
+        count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message2", mes);
+       // assertEquals("Assert count", 2, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        try {
+            configuration.delete();
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        ServiceReference ref = Utils.getServiceReference(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        assertNull("Check unavailability", ref);
+    }
+    
+    public void testDelayedCreationAndReconfiguration2() {
+        factory.stop();
+        //The reconfiguration happens before the service invocation
+        Configuration configuration = null;
+        try {
+            configuration = admin.createFactoryConfiguration("CA-ConfigurableProvider", null);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        Dictionary props = configuration.getProperties();
+        if(props == null) {
+            props = new Properties();
+        }
+        props.put("message", "message");
+        
+        try {
+            configuration.update(props);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        
+        String pid = configuration.getPid();
+        System.out.println("PID : " + pid);
+        
+        assertNull("check no instance", Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")"));
+        
+        factory.start();
+        
+        
+        //  The instance should be created, wait for the architecture service
+        Utils.waitForService(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        Architecture architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check no object", 0, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        props.put("message", "message2");
+        try {
+            configuration.update(props);
+            // Update the configuration ...
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Check no object -2", 0, architecture.getInstanceDescription().getCreatedObjects().length);
+        
+        //Invoke
+        FooService fs = (FooService) Utils.getServiceObject(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        Properties p = fs.fooProps();
+        String mes = p.getProperty("message");
+        int count = ((Integer) p.get("count")).intValue();
+        architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
+        
+        assertEquals("Assert Message", "message2", mes);
+        assertEquals("Assert count", 1, count);
+        assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
+                
+        try {
+            configuration.delete();
+            Thread.sleep(10);
+        } catch (Exception e) {
+            fail(e.getMessage());
+        }
+        
+        ServiceReference ref = Utils.getServiceReference(context, FooService.class.getName(), "(instance.name=" + pid + ")");
+        assertNull("Check unavailability", ref);
+    }
+    
+    
+
+}