Fix FELIX-4236 Unvalued properties should be part of the instance's architecture
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1525393 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/arch/MyComponentToIntrospect.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/arch/MyComponentToIntrospect.java
new file mode 100644
index 0000000..8ebb157
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/main/java/org/apache/felix/ipojo/runtime/core/components/arch/MyComponentToIntrospect.java
@@ -0,0 +1,95 @@
+/*
+ * 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.runtime.core.components.arch;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+
+import java.util.Properties;
+
+/**
+ * A component with properties with/without default values to check that the architecture contains all the required
+ * information.
+ *
+ * <ul>
+ * <li>p1 : the property has no value, the field has one</li>
+ * <li>p2 : the property has no value, it receives one in the constructor</li>
+ * <li>p3 : the property has a default value</li>
+ * <li>p4 : the property has a default value, overridden by the field value</li>
+ * <li>p5 : the property has a default value, overridden by the instance configuration</li>
+ * <li>p6 : the property has no value, the field is not initialized (not initialized means no value)</li>
+ * <li>p62 : the property has no value, the field is initialized to null </li>
+ * <li>p7 : the property has no value, it receives one in the constructor, but stay unused</li>
+ * <li>p8 : the property has no value, it does not receive one.</li>
+ * <li>p9 : the property has no value, it receives one in a method.</li>
+ * </ul>
+ */
+@Component(propagation = true)
+@Provides
+public class MyComponentToIntrospect implements CheckService {
+
+ @Property(name="p2")
+ private final String p2;
+
+ @Property
+ private String p1 = "v1";
+
+ @Property(name="p3", value = "v3")
+ private String p3;
+
+ @Property(value = "v4")
+ private String p4 = "v42";
+
+ @Property(value = "v5")
+ private String p5 = "v52";
+
+ @Property
+ private String p6;
+
+ @Property
+ private String p62 = null;
+
+ public MyComponentToIntrospect(@Property(name="p7") String v7) {
+ p2 = "v2";
+ }
+
+
+ @Property(name="p8")
+ public void setP8(String v8) {
+
+ }
+
+ @Property(name="p9")
+ public void setP9(String v9) {
+
+ }
+
+ @Override
+ public boolean check() {
+ return true;
+ }
+
+ @Override
+ public Properties getProps() {
+ return null;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestArchitecture.java b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestArchitecture.java
index 68a0a5d..8cbfc96 100644
--- a/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestArchitecture.java
+++ b/ipojo/runtime/core-it/ipojo-core-configuration-test/src/test/java/org/apache/felix/ipojo/runtime/core/TestArchitecture.java
@@ -20,18 +20,22 @@
package org.apache.felix.ipojo.runtime.core;
import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.PrimitiveInstanceDescription;
import org.apache.felix.ipojo.architecture.Architecture;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
import org.apache.felix.ipojo.handlers.configuration.ConfigurationHandlerDescription;
+import org.apache.felix.ipojo.runtime.core.services.CheckService;
+import org.apache.felix.ipojo.util.Property;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.osgi.framework.ServiceReference;
import java.util.Dictionary;
import java.util.Hashtable;
import static junit.framework.Assert.*;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
public class TestArchitecture extends Common {
@@ -149,5 +153,84 @@
assertNull(arch);
}
+ /**
+ * Checks the introspection possibilities before and after object creation.
+ * Especially check the 'unvalued' case.
+ */
+ @Test
+ public void testIntrospection() {
+ Dictionary<String, String> configuration = new Hashtable<String, String>();
+ configuration.put("p5", "v5i");
+ configuration.put("p7", "v7i");
+ configuration.put("p9", "v9i");
+
+ ComponentInstance instance = ipojoHelper.createComponentInstance(
+ "org.apache.felix.ipojo.runtime.core.components.arch.MyComponentToIntrospect",
+ configuration);
+
+ // We don't get the service object until we finished the pre-instantiation tests.
+ ServiceReference reference = osgiHelper.waitForService(CheckService.class.getName(),
+ "(instance.name=" + instance.getInstanceName() + ")", 1000);
+
+ assertNotNull(reference);
+
+ PropertyDescription[] properties = ((PrimitiveInstanceDescription) instance.getInstanceDescription())
+ .getProperties();
+
+ assertNotNull(properties);
+
+ // Check the properties.
+ assertEquals(getProperty(properties, "p1").getValue(), Property.UNVALUED);
+ assertEquals(getProperty(properties, "p2").getValue(), Property.UNVALUED);
+ assertEquals(getProperty(properties, "p3").getValue(), "v3"); // Default value
+ assertEquals(getProperty(properties, "p4").getValue(), "v4"); // Default value
+ assertEquals(getProperty(properties, "p5").getValue(), "v5i"); // Instance value
+ assertEquals(getProperty(properties, "p6").getValue(), Property.UNVALUED);
+ assertEquals(getProperty(properties, "p6").getValue(), Property.UNVALUED);
+ assertEquals(getProperty(properties, "p7").getValue(), "v7i"); // Instance value
+ assertEquals(getProperty(properties, "p8").getValue(), Property.UNVALUED);
+ assertEquals(getProperty(properties, "p9").getValue(), "v9i"); // Instance value
+
+ // Check the propagation
+ assertNull(reference.getProperty("p1"));
+ assertNull(reference.getProperty("p2"));
+ assertEquals(reference.getProperty("p3"), "v3");
+ assertEquals(reference.getProperty("p4"), "v4");
+ assertEquals(reference.getProperty("p5"), "v5i");
+ assertNull(reference.getProperty("p6"));
+ assertNull(reference.getProperty("p62"));
+ assertEquals(reference.getProperty("p7"), "v7i");
+ assertNull(reference.getProperty("p8"));
+ assertEquals(reference.getProperty("p9"), "v9i");
+
+ // Trigger instantiation
+ assertTrue(((CheckService) context.getService(reference)).check());
+
+ // Check new value.
+ assertEquals(getProperty(properties, "p1").getValue(), "v1");
+ assertEquals(getProperty(properties, "p2").getValue(), "v2");
+ assertEquals(getProperty(properties, "p3").getValue(), "v3"); // Default value
+ assertEquals(getProperty(properties, "p4").getValue(), "v42"); // Default value
+ assertEquals(getProperty(properties, "p5").getValue(), "v52"); // Field value
+ assertEquals(getProperty(properties, "p6").getValue(), Property.UNVALUED); // Specific value used for null
+ assertEquals(getProperty(properties, "p62").getValue(), "null"); // Specific value used for null
+ assertEquals(getProperty(properties, "p7").getValue(), "v7i"); // Instance value
+ assertEquals(getProperty(properties, "p8").getValue(), Property.UNVALUED);
+ assertEquals(getProperty(properties, "p9").getValue(), "v9i"); // Instance value
+
+ // New valued properties are not propagated.
+ // It avoids having fluctuation ins the service registrations
+ // To enable this propagation use @ServiceProperty
+ }
+
+ private PropertyDescription getProperty(PropertyDescription[] props, String name) {
+ for (PropertyDescription desc : props) {
+ if (desc.getName().equals(name)) {
+ return desc;
+ }
+ }
+ return null;
+ }
+
}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/PropertyDescription.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/PropertyDescription.java
index 4b037b4..a5a528f 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/PropertyDescription.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/architecture/PropertyDescription.java
@@ -132,6 +132,8 @@
Object value = m_property.getValue();
if (value == null) {
return "null";
+ } else if (value == Property.NO_VALUE) {
+ return Property.UNVALUED;
} else {
return value.toString();
}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
index 6ee8e4e..5942b3e 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
@@ -354,7 +354,19 @@
m_toPropagate.put(prop.getName(), prop.getValue());
}
}
- reconfigure(m_toPropagate);
+
+ // We cannot use the reconfigure method directly, as there are no real changes.
+ Properties extra = reconfigureProperties(m_toPropagate);
+ propagate(extra, m_propagatedFromInstance);
+ m_propagatedFromInstance = extra;
+
+ if (getInstanceManager().getPojoObjects() != null) {
+ try {
+ notifyUpdated(null);
+ } catch (Throwable e) {
+ error("Cannot call the updated method : " + e.getMessage(), e);
+ }
+ }
}
@@ -446,7 +458,6 @@
|| name.equals(MANAGED_SERVICE_PID)) {
continue;
}
-
// Do we have a property.
Property p = getPropertyByName(name);
if (p != null) {
@@ -623,7 +634,7 @@
/**
* Handler createInstance method.
* This method is override to allow delayed callback invocation.
- * Invokes the updated method is needed.
+ * Invokes the updated method if needed.
*
* @param instance : the created object
* @see org.apache.felix.ipojo.PrimitiveHandler#onCreation(Object)
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Property.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Property.java
index 301b5b3..0ebc880 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Property.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/util/Property.java
@@ -46,6 +46,11 @@
public static final Object NO_VALUE = new Object();
/**
+ * String value returned for property without values.
+ */
+ public static final String UNVALUED = "UNVALUED";
+
+ /**
* The name of the property (field name if not set).
* Cannot change once set.
*/