You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by gn...@apache.org on 2012/07/24 01:06:02 UTC
svn commit: r1364831 - in /aries/trunk/blueprint/blueprint-cm: ./
src/main/java/org/apache/aries/blueprint/compendium/cm/ src/test/
src/test/java/ src/test/java/org/ src/test/java/org/apache/
src/test/java/org/apache/aries/ src/test/java/org/apache/ari...
Author: gnodet
Date: Mon Jul 23 23:06:01 2012
New Revision: 1364831
URL: http://svn.apache.org/viewvc?rev=1364831&view=rev
Log:
[ARIES-878] Threading issues with <cm:managed-properties />
Added:
aries/trunk/blueprint/blueprint-cm/src/test/
aries/trunk/blueprint/blueprint-cm/src/test/java/
aries/trunk/blueprint/blueprint-cm/src/test/java/org/
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/BaseTest.java
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Foo.java
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/FooInterface.java
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Helper.java
aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.java
aries/trunk/blueprint/blueprint-cm/src/test/resources/
aries/trunk/blueprint/blueprint-cm/src/test/resources/log4j.properties
aries/trunk/blueprint/blueprint-cm/src/test/resources/org/
aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/
aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/aries/
aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/aries/blueprint/
aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/aries/blueprint/compendium/
aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/aries/blueprint/compendium/cm/
aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.xml
Modified:
aries/trunk/blueprint/blueprint-cm/pom.xml
aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java
aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java
aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java
Modified: aries/trunk/blueprint/blueprint-cm/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/pom.xml?rev=1364831&r1=1364830&r2=1364831&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/pom.xml (original)
+++ aries/trunk/blueprint/blueprint-cm/pom.xml Mon Jul 23 23:06:01 2012
@@ -101,6 +101,48 @@
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>com.googlecode.pojosr</groupId>
+ <artifactId>de.kalpatec.pojosr.framework</artifactId>
+ <version>0.1.6</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.swissbox</groupId>
+ <artifactId>pax-swissbox-tinybundles</artifactId>
+ <version>1.3.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.5.11</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ <version>1.5.11</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.proxy</groupId>
+ <artifactId>org.apache.aries.proxy.impl</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.configadmin</artifactId>
+ <version>1.2.8</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
Modified: aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java?rev=1364831&r1=1364830&r2=1364831&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java (original)
+++ aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmManagedProperties.java Mon Jul 23 23:06:01 2012
@@ -150,17 +150,12 @@ public class CmManagedProperties impleme
public void updated(final Dictionary props) {
LOGGER.debug("Configuration updated for bean={} / pid={}", beanName, persistentId);
- // Run in a separate thread to avoid re-entrance
- new Thread() {
- public void run() {
- synchronized (lock) {
- properties = props;
- for (Object bean : beans) {
- inject(bean, false);
- }
- }
+ synchronized (lock) {
+ properties = props;
+ for (Object bean : beans) {
+ inject(bean, false);
}
- }.start();
+ }
}
public Object beforeInit(Object bean, String beanName, BeanCreator beanCreator, BeanMetadata beanData) {
Modified: aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java?rev=1364831&r1=1364830&r2=1364831&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java (original)
+++ aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java Mon Jul 23 23:06:01 2012
@@ -24,19 +24,13 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Properties;
import java.util.Set;
-import org.apache.aries.blueprint.ext.PlaceholdersUtils;
-import org.w3c.dom.CharacterData;
-import org.w3c.dom.Comment;
-import org.w3c.dom.Element;
-import org.w3c.dom.EntityReference;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
import org.apache.aries.blueprint.ComponentDefinitionRegistry;
import org.apache.aries.blueprint.NamespaceHandler;
import org.apache.aries.blueprint.ParserContext;
+import org.apache.aries.blueprint.ext.PlaceholdersUtils;
import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
import org.apache.aries.blueprint.mutable.MutableCollectionMetadata;
import org.apache.aries.blueprint.mutable.MutableComponentMetadata;
@@ -46,7 +40,6 @@ import org.apache.aries.blueprint.mutabl
import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
import org.apache.aries.blueprint.mutable.MutableValueMetadata;
import org.apache.aries.blueprint.utils.ServiceListener;
-import org.osgi.framework.BundleContext;
import org.osgi.service.blueprint.container.ComponentDefinitionException;
import org.osgi.service.blueprint.reflect.BeanMetadata;
import org.osgi.service.blueprint.reflect.BeanProperty;
@@ -63,6 +56,12 @@ import org.osgi.service.blueprint.reflec
import org.osgi.service.cm.ConfigurationAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.w3c.dom.CharacterData;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Element;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/**
* Namespace handler for the Config Admin service.
@@ -240,8 +239,7 @@ public class CmNamespaceHandler implemen
Node node = nl.item(i);
if (node instanceof Element) {
Element e = (Element) node;
- if (BLUEPRINT_CM_NAMESPACE_1_0.equals(e.getNamespaceURI())
- || BLUEPRINT_CM_NAMESPACE_1_1.equals(e.getNamespaceURI())) {
+ if (isCmNamespace(e.getNamespaceURI())) {
if (nodeNameEquals(e, DEFAULT_PROPERTIES_ELEMENT)) {
if (defaultsRef != null) {
throw new ComponentDefinitionException("Only one of " + DEFAULTS_REF_ATTRIBUTE + " attribute or " + DEFAULT_PROPERTIES_ELEMENT + " element is allowed");
@@ -249,9 +247,7 @@ public class CmNamespaceHandler implemen
Metadata props = parseDefaultProperties(context, metadata, e);
metadata.addProperty("defaultProperties", props);
}
- } else if (BLUEPRINT_EXT_NAMESPACE_V1_0.equals(e.getNamespaceURI())
- || BLUEPRINT_EXT_NAMESPACE_V1_1.equals(e.getNamespaceURI())
- || BLUEPRINT_EXT_NAMESPACE_V1_2.equals(e.getNamespaceURI())) {
+ } else if (isExtNamespace(e.getNamespaceURI())) {
if (nodeNameEquals(e, LOCATION_ELEMENT)) {
locations.add(getTextValue(e));
}
@@ -299,8 +295,7 @@ public class CmNamespaceHandler implemen
Node node = nl.item(i);
if (node instanceof Element) {
Element e = (Element) node;
- if (BLUEPRINT_CM_NAMESPACE_1_0.equals(e.getNamespaceURI())
- || BLUEPRINT_CM_NAMESPACE_1_1.equals(e.getNamespaceURI())) {
+ if (isCmNamespace(e.getNamespaceURI())) {
if (nodeNameEquals(e, PROPERTY_ELEMENT)) {
BeanProperty prop = context.parseElement(BeanProperty.class, enclosingComponent, e);
props.addEntry(createValue(context, prop.getName(), String.class.getName()), prop.getValue());
@@ -364,12 +359,20 @@ public class CmNamespaceHandler implemen
MapMetadata map = context.parseElement(MapMetadata.class,
factoryMetadata, e);
factoryMetadata.addProperty("serviceProperties", map);
+ NodeList enl = e.getChildNodes();
+ for (int j = 0; j < enl.getLength(); j++) {
+ Node enode = enl.item(j);
+ if (enode instanceof Element) {
+ if (isCmNamespace(enode.getNamespaceURI()) && nodeNameEquals(enode, CM_PROPERTIES_ELEMENT)) {
+ decorateCmProperties(context, (Element) enode, factoryMetadata);
+ }
+ }
+ }
} else if (nodeNameEquals(e, REGISTRATION_LISTENER_ELEMENT)) {
listeners.add(context.parseElement(RegistrationListener.class,
factoryMetadata, e));
}
- } else if (BLUEPRINT_CM_NAMESPACE_1_0.equals(e.getNamespaceURI())
- || BLUEPRINT_CM_NAMESPACE_1_1.equals(e.getNamespaceURI())) {
+ } else if (isCmNamespace(e.getNamespaceURI())) {
if (nodeNameEquals(e, MANAGED_COMPONENT_ELEMENT)) {
MutableBeanMetadata managedComponent = context.parseElement(MutableBeanMetadata.class, null, e);
generateIdIfNeeded(context, managedComponent);
@@ -482,7 +485,7 @@ public class CmNamespaceHandler implemen
}
private MutableReferenceMetadata createConfigurationAdminRef(ParserContext context) {
- return createServiceRef(context, ConfigurationAdmin.class, "(objectClass=" + ConfigurationAdmin.class.getName() + ")");
+ return createServiceRef(context, ConfigurationAdmin.class, null);
}
private static ValueMetadata createValue(ParserContext context, String value) {
@@ -552,6 +555,17 @@ public class CmNamespaceHandler implemen
return BLUEPRINT_NAMESPACE.equals(ns);
}
+ public static boolean isCmNamespace(String uri) {
+ return BLUEPRINT_CM_NAMESPACE_1_0.equals(uri)
+ || BLUEPRINT_CM_NAMESPACE_1_1.equals(uri);
+ }
+
+ public static boolean isExtNamespace(String uri) {
+ return BLUEPRINT_EXT_NAMESPACE_V1_0.equals(uri)
+ || BLUEPRINT_EXT_NAMESPACE_V1_1.equals(uri)
+ || BLUEPRINT_EXT_NAMESPACE_V1_2.equals(uri);
+ }
+
public String getId(ParserContext context, Element element) {
if (element.hasAttribute(ID_ATTRIBUTE)) {
return element.getAttribute(ID_ATTRIBUTE);
Modified: aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java?rev=1364831&r1=1364830&r2=1364831&view=diff
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java (original)
+++ aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ManagedObjectManager.java Mon Jul 23 23:06:01 2012
@@ -18,12 +18,11 @@
*/
package org.apache.aries.blueprint.compendium.cm;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.aries.util.AriesFrameworkUtil;
import org.osgi.framework.ServiceRegistration;
@@ -69,17 +68,20 @@ public class ManagedObjectManager {
private static class ConfigurationWatcher implements ManagedService {
private ServiceRegistration registration;
- private List<ManagedObject> list = Collections.synchronizedList(new ArrayList<ManagedObject>());
+ private List<ManagedObject> list = new CopyOnWriteArrayList<ManagedObject>();
public ConfigurationWatcher() {
}
- public void updated(Dictionary props) throws ConfigurationException {
- synchronized (list) {
- for (ManagedObject cm : list) {
- cm.updated(props);
+ public void updated(final Dictionary props) throws ConfigurationException {
+ // Run in a separate thread to avoid re-entrance
+ new Thread() {
+ public void run() {
+ for (ManagedObject cm : list) {
+ cm.updated(props);
+ }
}
- }
+ }.start();
}
private void setRegistration(ServiceRegistration registration) {
Added: aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/BaseTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/BaseTest.java?rev=1364831&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/BaseTest.java (added)
+++ aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/BaseTest.java Mon Jul 23 23:06:01 2012
@@ -0,0 +1,111 @@
+/**
+ * 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.aries.blueprint.compendium.cm;
+
+import org.junit.After;
+import org.junit.Before;
+import org.ops4j.pax.swissbox.tinybundles.core.TinyBundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.blueprint.container.BlueprintContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class BaseTest {
+
+ private BundleContext bundleContext;
+ protected transient Logger log = LoggerFactory.getLogger(getClass());
+
+ @Before
+ public void setUp() throws Exception {
+ String symbolicName = getClass().getSimpleName();
+
+ TinyBundle cmBundle = Helper.createTestBundle("blueprint-cm", "1.0.0.SNAPSHOT", "OSGI-INF/blueprint/blueprint-cm.xml");
+ TinyBundle testBundle = Helper.createTestBundle(symbolicName, "1.0.0.SNAPSHOT", getBlueprintDescriptor());
+
+ this.bundleContext = Helper.createBundleContext(getBundleFilter(), new TinyBundle[] { cmBundle, testBundle });
+
+ // must wait for blueprint container to be published then the namespace parser is complete and we are ready for testing
+ log.debug("Waiting for BlueprintContainer to be published with symbolicName: {}", symbolicName);
+ getOsgiService(BlueprintContainer.class, "(osgi.blueprint.container.symbolicname=" + symbolicName + ")");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Helper.disposeBundleContext(bundleContext);
+ }
+
+ /**
+ * Return the system bundle context
+ * @return
+ */
+ protected BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ /**
+ * Gets the bundle descriptor from the classpath.
+ * <p/>
+ * Return the location(s) of the bundle descriptors from the classpath.
+ * Separate multiple locations by comma, or return a single location.
+ * <p/>
+ * For example override this method and return <tt>OSGI-INF/blueprint/camel-context.xml</tt>
+ *
+ * @return the location of the bundle descriptor file.
+ */
+ protected String getBlueprintDescriptor() {
+ return null;
+ }
+
+ /**
+ * Gets filter expression of bundle descriptors.
+ * Modify this method if you wish to change default behavior.
+ *
+ * @return filter expression for OSGi bundles.
+ */
+ protected String getBundleFilter() {
+ return Helper.BUNDLE_FILTER;
+ }
+
+ /**
+ * Gets test bundle version.
+ * Modify this method if you wish to change default behavior.
+ *
+ * @return test bundle version
+ */
+ protected String getBundleVersion() {
+ return Helper.BUNDLE_VERSION;
+ }
+
+ protected <T> T getOsgiService(Class<T> type) {
+ return Helper.getOsgiService(bundleContext, type);
+ }
+
+ protected <T> T getOsgiService(Class<T> type, long timeout) {
+ return Helper.getOsgiService(bundleContext, type, timeout);
+ }
+
+ protected <T> T getOsgiService(Class<T> type, String filter) {
+ return Helper.getOsgiService(bundleContext, type, filter);
+ }
+
+ protected <T> T getOsgiService(Class<T> type, String filter, long timeout) {
+ return Helper.getOsgiService(bundleContext, type, filter, timeout);
+ }
+
+}
Added: aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Foo.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Foo.java?rev=1364831&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Foo.java (added)
+++ aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Foo.java Mon Jul 23 23:06:01 2012
@@ -0,0 +1,56 @@
+/**
+ * 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.aries.blueprint.compendium.cm;
+
+import java.util.Properties;
+
+public class Foo implements FooInterface {
+
+ public Foo() {
+ }
+
+ private int a;
+ private String b;
+ private Properties props;
+
+ public int getA() {
+ return a;
+ }
+
+ public void setA(int i) {
+ a = i;
+ }
+
+ public String getB() {
+ return b;
+ }
+
+ public void setB(String i) {
+ b = i;
+ }
+
+ public Properties getProps() {
+ return props;
+ }
+
+ public void setProps(Properties props) {
+ this.props = props;
+ }
+}
+
Added: aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/FooInterface.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/FooInterface.java?rev=1364831&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/FooInterface.java (added)
+++ aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/FooInterface.java Mon Jul 23 23:06:01 2012
@@ -0,0 +1,27 @@
+/**
+ * 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.aries.blueprint.compendium.cm;
+
+import java.util.Properties;
+
+public interface FooInterface {
+
+ Properties getProps();
+
+}
Added: aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Helper.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Helper.java?rev=1364831&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Helper.java (added)
+++ aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/Helper.java Mon Jul 23 23:06:01 2012
@@ -0,0 +1,781 @@
+/**
+ * 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.aries.blueprint.compendium.cm;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.jar.JarInputStream;
+
+import de.kalpatec.pojosr.framework.PojoServiceRegistryFactoryImpl;
+import de.kalpatec.pojosr.framework.launch.BundleDescriptor;
+import de.kalpatec.pojosr.framework.launch.ClasspathScanner;
+import de.kalpatec.pojosr.framework.launch.PojoServiceRegistry;
+import de.kalpatec.pojosr.framework.launch.PojoServiceRegistryFactory;
+import org.ops4j.pax.swissbox.tinybundles.core.TinyBundle;
+import org.ops4j.pax.swissbox.tinybundles.core.TinyBundles;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public final class Helper {
+
+ public static final long DEFAULT_TIMEOUT = 30000;
+ public static final String BUNDLE_FILTER = "(Bundle-SymbolicName=*)";
+ public static final String BUNDLE_VERSION = "1.0.0";
+ private static final transient Logger LOG = LoggerFactory.getLogger(Helper.class);
+
+ private Helper() {
+ }
+
+ public static BundleContext createBundleContext(String name, String descriptors, boolean includeTestBundle) throws Exception {
+ return createBundleContext(name, descriptors, includeTestBundle, BUNDLE_FILTER, BUNDLE_VERSION);
+ }
+
+ public static BundleContext createBundleContext(String name, String descriptors, boolean includeTestBundle,
+ String bundleFilter, String testBundleVersion) throws Exception {
+ TinyBundle bundle = null;
+
+ if (includeTestBundle) {
+ // add ourselves as a bundle
+ bundle = createTestBundle(name, testBundleVersion, descriptors);
+ }
+
+ return createBundleContext(bundleFilter, new TinyBundle[] { bundle });
+ }
+
+ public static BundleContext createBundleContext(String bundleFilter, TinyBundle[] testBundles) throws Exception {
+ deleteDirectory("target/bundles");
+ createDirectory("target/bundles");
+
+ // ensure pojosr stores bundles in an unique target directory
+ System.setProperty("org.osgi.framework.storage", "target/bundles/" + System.currentTimeMillis());
+
+ // get the bundles
+ List<BundleDescriptor> bundles = getBundleDescriptors(bundleFilter);
+
+ if (testBundles != null) {
+ for (TinyBundle bundle : testBundles) {
+ File tmp = File.createTempFile("test-", ".jar", new File("target/bundles/"));
+ tmp.delete();
+ bundles.add(getBundleDescriptor(tmp.getPath(), bundle));
+ }
+ }
+
+ if (LOG.isDebugEnabled()) {
+ for (int i = 0; i < bundles.size(); i++) {
+ BundleDescriptor desc = bundles.get(i);
+ LOG.debug("Bundle #{} -> {}", i, desc);
+ }
+ }
+
+ // setup pojosr to use our bundles
+ Map<String, List<BundleDescriptor>> config = new HashMap<String, List<BundleDescriptor>>();
+ config.put(PojoServiceRegistryFactory.BUNDLE_DESCRIPTORS, bundles);
+
+ // create pojorsr osgi service registry
+ PojoServiceRegistry reg = new PojoServiceRegistryFactoryImpl().newPojoServiceRegistry(config);
+ return reg.getBundleContext();
+ }
+
+ public static void disposeBundleContext(BundleContext bundleContext) throws BundleException {
+ try {
+ if (bundleContext != null) {
+ bundleContext.getBundle().stop();
+ }
+ } finally {
+ System.clearProperty("org.osgi.framework.storage");
+ }
+ }
+
+ public static <T> T getOsgiService(BundleContext bundleContext, Class<T> type, long timeout) {
+ return getOsgiService(bundleContext, type, null, timeout);
+ }
+
+ public static <T> T getOsgiService(BundleContext bundleContext, Class<T> type) {
+ return getOsgiService(bundleContext, type, null, DEFAULT_TIMEOUT);
+ }
+
+ public static <T> T getOsgiService(BundleContext bundleContext, Class<T> type, String filter) {
+ return getOsgiService(bundleContext, type, filter, DEFAULT_TIMEOUT);
+ }
+
+ public static <T> ServiceReference getOsgiServiceReference(BundleContext bundleContext, Class<T> type, String filter, long timeout) {
+ ServiceTracker tracker = null;
+ try {
+ String flt;
+ if (filter != null) {
+ if (filter.startsWith("(")) {
+ flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")" + filter + ")";
+ } else {
+ flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")(" + filter + "))";
+ }
+ } else {
+ flt = "(" + Constants.OBJECTCLASS + "=" + type.getName() + ")";
+ }
+ Filter osgiFilter = FrameworkUtil.createFilter(flt);
+ tracker = new ServiceTracker(bundleContext, osgiFilter, null);
+ tracker.open(true);
+ // Note that the tracker is not closed to keep the reference
+ // This is buggy, as the service reference may change i think
+ Object svc = tracker.waitForService(timeout);
+ if (svc == null) {
+ Dictionary<?, ?> dic = bundleContext.getBundle().getHeaders();
+ System.err.println("Test bundle headers: " + explode(dic));
+
+ for (ServiceReference ref : asCollection(bundleContext.getAllServiceReferences(null, null))) {
+ System.err.println("ServiceReference: " + ref + ", bundle: " + ref.getBundle() + ", symbolicName: " + ref.getBundle().getSymbolicName());
+ }
+
+ for (ServiceReference ref : asCollection(bundleContext.getAllServiceReferences(null, flt))) {
+ System.err.println("Filtered ServiceReference: " + ref + ", bundle: " + ref.getBundle() + ", symbolicName: " + ref.getBundle().getSymbolicName());
+ }
+
+ throw new RuntimeException("Gave up waiting for service " + flt);
+ }
+ return tracker.getServiceReference();
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Invalid filter", e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static <T> T getOsgiService(BundleContext bundleContext, Class<T> type, String filter, long timeout) {
+ ServiceTracker tracker = null;
+ try {
+ String flt;
+ if (filter != null) {
+ if (filter.startsWith("(")) {
+ flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")" + filter + ")";
+ } else {
+ flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")(" + filter + "))";
+ }
+ } else {
+ flt = "(" + Constants.OBJECTCLASS + "=" + type.getName() + ")";
+ }
+ Filter osgiFilter = FrameworkUtil.createFilter(flt);
+ tracker = new ServiceTracker(bundleContext, osgiFilter, null);
+ tracker.open(true);
+ // Note that the tracker is not closed to keep the reference
+ // This is buggy, as the service reference may change i think
+ Object svc = tracker.waitForService(timeout);
+ if (svc == null) {
+ Dictionary<?, ?> dic = bundleContext.getBundle().getHeaders();
+ System.err.println("Test bundle headers: " + explode(dic));
+
+ for (ServiceReference ref : asCollection(bundleContext.getAllServiceReferences(null, null))) {
+ System.err.println("ServiceReference: " + ref + ", bundle: " + ref.getBundle() + ", symbolicName: " + ref.getBundle().getSymbolicName());
+ }
+
+ for (ServiceReference ref : asCollection(bundleContext.getAllServiceReferences(null, flt))) {
+ System.err.println("Filtered ServiceReference: " + ref + ", bundle: " + ref.getBundle() + ", symbolicName: " + ref.getBundle().getSymbolicName());
+ }
+
+ throw new RuntimeException("Gave up waiting for service " + flt);
+ }
+ return type.cast(svc);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalArgumentException("Invalid filter", e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected static TinyBundle createTestBundle(String name, String version, String descriptors) throws FileNotFoundException, MalformedURLException {
+ TinyBundle bundle = TinyBundles.newBundle();
+ for (URL url : getBlueprintDescriptors(descriptors)) {
+ LOG.info("Using Blueprint XML file: " + url.getFile());
+ bundle.add("OSGI-INF/blueprint/blueprint-" + url.getFile().replace("/", "-"), url);
+ }
+ bundle.set("Manifest-Version", "2")
+ .set("Bundle-ManifestVersion", "2")
+ .set("Bundle-SymbolicName", name)
+ .set("Bundle-Version", version);
+ return bundle;
+ }
+
+ /**
+ * Explode the dictionary into a <code>,</code> delimited list of <code>key=value</code> pairs.
+ */
+ private static String explode(Dictionary<?, ?> dictionary) {
+ Enumeration<?> keys = dictionary.keys();
+ StringBuffer result = new StringBuffer();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ result.append(String.format("%s=%s", key, dictionary.get(key)));
+ if (keys.hasMoreElements()) {
+ result.append(", ");
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * Provides an iterable collection of references, even if the original array is <code>null</code>.
+ */
+ private static Collection<ServiceReference> asCollection(ServiceReference[] references) {
+ return references == null ? new ArrayList<ServiceReference>(0) : Arrays.asList(references);
+ }
+
+ /**
+ * Gets list of bundle descriptors.
+ * @param bundleFilter Filter expression for OSGI bundles.
+ *
+ * @return List pointers to OSGi bundles.
+ * @throws Exception If looking up the bundles fails.
+ */
+ private static List<BundleDescriptor> getBundleDescriptors(final String bundleFilter) throws Exception {
+ return new ClasspathScanner().scanForBundles(bundleFilter);
+ }
+
+ /**
+ * Gets the bundle descriptors as {@link URL} resources.
+ *
+ * @param descriptors the bundle descriptors, can be separated by comma
+ * @return the bundle descriptors.
+ * @throws FileNotFoundException is thrown if a bundle descriptor cannot be found
+ */
+ private static Collection<URL> getBlueprintDescriptors(String descriptors) throws FileNotFoundException, MalformedURLException {
+ List<URL> answer = new ArrayList<URL>();
+ String descriptor = descriptors;
+ if (descriptor != null) {
+ // there may be more resources separated by comma
+ Iterator<Object> it = createIterator(descriptor);
+ while (it.hasNext()) {
+ String s = (String) it.next();
+ LOG.trace("Resource descriptor: {}", s);
+
+ // remove leading / to be able to load resource from the classpath
+ s = stripLeadingSeparator(s);
+
+ // if there is wildcards for *.xml then we need to find the urls from the package
+ if (s.endsWith("*.xml")) {
+ String packageName = s.substring(0, s.length() - 5);
+ // remove trailing / to be able to load resource from the classpath
+ Enumeration<URL> urls = loadResourcesAsURL(packageName);
+ while (urls.hasMoreElements()) {
+ URL url = urls.nextElement();
+ File dir = new File(url.getFile());
+ if (dir.isDirectory()) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isFile() && file.exists() && file.getName().endsWith(".xml")) {
+ String name = packageName + file.getName();
+ LOG.debug("Resolving resource: {}", name);
+ URL xmlUrl = loadResourceAsURL(name);
+ if (xmlUrl != null) {
+ answer.add(xmlUrl);
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ LOG.debug("Resolving resource: {}", s);
+ URL url = resolveMandatoryResourceAsUrl(s);
+ if (url == null) {
+ throw new FileNotFoundException("Resource " + s + " not found");
+ }
+ answer.add(url);
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("No bundle descriptor configured. Override getBlueprintDescriptor() or getBlueprintDescriptors() method");
+ }
+
+ if (answer.isEmpty()) {
+ throw new IllegalArgumentException("Cannot find any resources in classpath from descriptor " + descriptors);
+ }
+ return answer;
+ }
+
+ private static BundleDescriptor getBundleDescriptor(String path, TinyBundle bundle) throws Exception {
+ File file = new File(path);
+ FileOutputStream fos = new FileOutputStream(file, true);
+ try {
+ copy(bundle.build(), fos);
+ } finally {
+ close(fos);
+ }
+
+ FileInputStream fis = null;
+ JarInputStream jis = null;
+ try {
+ fis = new FileInputStream(file);
+ jis = new JarInputStream(fis);
+ Map<String, String> headers = new HashMap<String, String>();
+ for (Map.Entry<Object, Object> entry : jis.getManifest().getMainAttributes().entrySet()) {
+ headers.put(entry.getKey().toString(), entry.getValue().toString());
+ }
+
+ return new BundleDescriptor(
+ bundle.getClass().getClassLoader(),
+ new URL("jar:" + file.toURI().toString() + "!/"),
+ headers);
+ } finally {
+ close(fis, jis);
+ }
+ }
+
+ /**
+ * Closes the given resource if it is available, logging any closing exceptions to the given log.
+ *
+ * @param closeable the object to close
+ * @param name the name of the resource
+ * @param log the log to use when reporting closure warnings, will use this class's own {@link Logger} if <tt>log == null</tt>
+ */
+ public static void close(Closeable closeable, String name, Logger log) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (IOException e) {
+ if (log == null) {
+ // then fallback to use the own Logger
+ log = LOG;
+ }
+ if (name != null) {
+ log.warn("Cannot close: " + name + ". Reason: " + e.getMessage(), e);
+ } else {
+ log.warn("Cannot close. Reason: " + e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Closes the given resource if it is available.
+ *
+ * @param closeable the object to close
+ * @param name the name of the resource
+ */
+ public static void close(Closeable closeable, String name) {
+ close(closeable, name, LOG);
+ }
+
+ /**
+ * Closes the given resource if it is available.
+ *
+ * @param closeable the object to close
+ */
+ public static void close(Closeable closeable) {
+ close(closeable, null, LOG);
+ }
+
+ /**
+ * Closes the given resources if they are available.
+ *
+ * @param closeables the objects to close
+ */
+ public static void close(Closeable... closeables) {
+ for (Closeable closeable : closeables) {
+ close(closeable);
+ }
+ }
+
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+ private static final String DEFAULT_DELIMITER = ",";
+
+ public static int copy(InputStream input, OutputStream output) throws IOException {
+ return copy(input, output, DEFAULT_BUFFER_SIZE);
+ }
+
+ public static int copy(final InputStream input, final OutputStream output, int bufferSize) throws IOException {
+ int avail = input.available();
+ if (avail > 262144) {
+ avail = 262144;
+ }
+ if (avail > bufferSize) {
+ bufferSize = avail;
+ }
+
+ final byte[] buffer = new byte[bufferSize];
+ int n = input.read(buffer);
+ int total = 0;
+ while (-1 != n) {
+ output.write(buffer, 0, n);
+ total += n;
+ n = input.read(buffer);
+ }
+ output.flush();
+ return total;
+ }
+
+ /**
+ * Creates an iterator over the value if the value is a collection, an
+ * Object[], a String with values separated by comma,
+ * or a primitive type array; otherwise to simplify the caller's code,
+ * we just create a singleton collection iterator over a single value
+ * <p/>
+ * Will default use comma for String separating String values.
+ * This method does <b>not</b> allow empty values
+ *
+ * @param value the value
+ * @return the iterator
+ */
+ public static Iterator<Object> createIterator(Object value) {
+ return createIterator(value, DEFAULT_DELIMITER);
+ }
+
+ /**
+ * Creates an iterator over the value if the value is a collection, an
+ * Object[], a String with values separated by the given delimiter,
+ * or a primitive type array; otherwise to simplify the caller's
+ * code, we just create a singleton collection iterator over a single value
+ * <p/>
+ * This method does <b>not</b> allow empty values
+ *
+ * @param value the value
+ * @param delimiter delimiter for separating String values
+ * @return the iterator
+ */
+ public static Iterator<Object> createIterator(Object value, String delimiter) {
+ return createIterator(value, delimiter, false);
+ }
+
+ /**
+ * Creates an iterator over the value if the value is a collection, an
+ * Object[], a String with values separated by the given delimiter,
+ * or a primitive type array; otherwise to simplify the caller's
+ * code, we just create a singleton collection iterator over a single value
+ *
+ * @param value the value
+ * @param delimiter delimiter for separating String values
+ * @param allowEmptyValues whether to allow empty values
+ * @return the iterator
+ */
+ @SuppressWarnings("unchecked")
+ public static Iterator<Object> createIterator(Object value, String delimiter, final boolean allowEmptyValues) {
+ if (value == null) {
+ return Collections.emptyList().iterator();
+ } else if (value instanceof Iterator) {
+ return (Iterator<Object>)value;
+ } else if (value instanceof Iterable) {
+ return ((Iterable<Object>)value).iterator();
+ } else if (value.getClass().isArray()) {
+ // TODO we should handle primitive array types?
+ List<Object> list = Arrays.asList((Object[])value);
+ return list.iterator();
+ } else if (value instanceof NodeList) {
+ // lets iterate through DOM results after performing XPaths
+ final NodeList nodeList = (NodeList) value;
+ return cast(new Iterator<Node>() {
+ int idx = -1;
+
+ public boolean hasNext() {
+ return (idx + 1) < nodeList.getLength();
+ }
+
+ public Node next() {
+ idx++;
+ return nodeList.item(idx);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ });
+ } else if (value instanceof String) {
+ final String s = (String) value;
+
+ // this code is optimized to only use a Scanner if needed, eg there is a delimiter
+
+ if (delimiter != null && s.contains(delimiter)) {
+ // use a scanner if it contains the delimiter
+ Scanner scanner = new Scanner((String)value);
+
+ if (DEFAULT_DELIMITER.equals(delimiter)) {
+ // we use the default delimiter which is a comma, then cater for bean expressions with OGNL
+ // which may have balanced parentheses pairs as well.
+ // if the value contains parentheses we need to balance those, to avoid iterating
+ // in the middle of parentheses pair, so use this regular expression (a bit hard to read)
+ // the regexp will split by comma, but honor parentheses pair that may include commas
+ // as well, eg if value = "bean=foo?method=killer(a,b),bean=bar?method=great(a,b)"
+ // then the regexp will split that into two:
+ // -> bean=foo?method=killer(a,b)
+ // -> bean=bar?method=great(a,b)
+ // http://stackoverflow.com/questions/1516090/splitting-a-title-into-separate-parts
+ delimiter = ",(?!(?:[^\\(,]|[^\\)],[^\\)])+\\))";
+ }
+
+ scanner.useDelimiter(delimiter);
+ return cast(scanner);
+ } else {
+ // use a plain iterator that returns the value as is as there are only a single value
+ return cast(new Iterator<String>() {
+ int idx = -1;
+
+ public boolean hasNext() {
+ return idx + 1 == 0 && (allowEmptyValues || isNotEmpty(s));
+ }
+
+ public String next() {
+ idx++;
+ return s;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ });
+ }
+ } else {
+ return Collections.singletonList(value).iterator();
+ }
+ }
+
+ /**
+ * Tests whether the value is <b>not</b> <tt>null</tt> or an empty string.
+ *
+ * @param value the value, if its a String it will be tested for text length as well
+ * @return true if <b>not</b> empty
+ */
+ public static boolean isNotEmpty(Object value) {
+ if (value == null) {
+ return false;
+ } else if (value instanceof String) {
+ String text = (String) value;
+ return text.trim().length() > 0;
+ } else {
+ return true;
+ }
+ }
+
+ public static <T> Iterator<T> cast(Iterator<?> p) {
+ return (Iterator<T>) p;
+ }
+
+ /**
+ * Strip any leading separators
+ */
+ public static String stripLeadingSeparator(String name) {
+ if (name == null) {
+ return null;
+ }
+ while (name.startsWith("/") || name.startsWith(File.separator)) {
+ name = name.substring(1);
+ }
+ return name;
+ }
+
+ /**
+ * Attempts to load the given resources from the given package name using the thread context
+ * class loader or the class loader used to load this class
+ *
+ * @param packageName the name of the package to load its resources
+ * @return the URLs for the resources or null if it could not be loaded
+ */
+ public static Enumeration<URL> loadResourcesAsURL(String packageName) {
+ Enumeration<URL> url = null;
+
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ if (contextClassLoader != null) {
+ try {
+ url = contextClassLoader.getResources(packageName);
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ if (url == null) {
+ try {
+ url = Helper.class.getClassLoader().getResources(packageName);
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ return url;
+ }
+
+ /**
+ * Attempts to load the given resource as a stream using the thread context
+ * class loader or the class loader used to load this class
+ *
+ * @param name the name of the resource to load
+ * @return the stream or null if it could not be loaded
+ */
+ public static URL loadResourceAsURL(String name) {
+ URL url = null;
+
+ String resolvedName = resolveUriPath(name);
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ if (contextClassLoader != null) {
+ url = contextClassLoader.getResource(resolvedName);
+ }
+ if (url == null) {
+ url = Helper.class.getClassLoader().getResource(resolvedName);
+ }
+
+ return url;
+ }
+
+ /**
+ * Helper operation used to remove relative path notation from
+ * resources. Most critical for resources on the Classpath
+ * as resource loaders will not resolve the relative paths correctly.
+ *
+ * @param name the name of the resource to load
+ * @return the modified or unmodified string if there were no changes
+ */
+ private static String resolveUriPath(String name) {
+ String answer = name;
+ if (answer.indexOf("//") > -1) {
+ answer = answer.replaceAll("//", "/");
+ }
+ if (answer.indexOf("../") > -1) {
+ answer = answer.replaceAll("[A-Za-z0-9]*/\\.\\./", "");
+ }
+ if (answer.indexOf("./") > -1) {
+ answer = answer.replaceAll("\\./", "");
+ }
+ return answer;
+ }
+
+ /**
+ * Resolves the mandatory resource.
+ *
+ * @param uri uri of the resource
+ * @return the resource as an {@link InputStream}. Remember to close this stream after usage.
+ * @throws java.io.FileNotFoundException is thrown if the resource file could not be found
+ * @throws java.net.MalformedURLException if the URI is malformed
+ */
+ public static URL resolveMandatoryResourceAsUrl(String uri) throws FileNotFoundException, MalformedURLException {
+ if (uri.startsWith("file:")) {
+ // check if file exists first
+ String name = after(uri, "file:");
+ File file = new File(name);
+ if (!file.exists()) {
+ throw new FileNotFoundException("File " + file + " not found");
+ }
+ return new URL(uri);
+ } else if (uri.startsWith("http:")) {
+ return new URL(uri);
+ } else if (uri.startsWith("classpath:")) {
+ uri = after(uri, "classpath:");
+ }
+
+ // load from classpath by default
+ URL url = loadResourceAsURL(uri);
+ if (url == null) {
+ throw new FileNotFoundException("Cannot find resource in classpath for URI: " + uri);
+ } else {
+ return url;
+ }
+ }
+
+ public static String after(String text, String after) {
+ if (!text.contains(after)) {
+ return null;
+ }
+ return text.substring(text.indexOf(after) + after.length());
+ }
+
+ /**
+ * Recursively delete a directory, useful to zapping test data
+ *
+ * @param file the directory to be deleted
+ * @return <tt>false</tt> if error deleting directory
+ */
+ public static boolean deleteDirectory(String file) {
+ return deleteDirectory(new File(file));
+ }
+
+ /**
+ * Recursively delete a directory, useful to zapping test data
+ *
+ * @param file the directory to be deleted
+ * @return <tt>false</tt> if error deleting directory
+ */
+ public static boolean deleteDirectory(File file) {
+ int tries = 0;
+ int maxTries = 5;
+ boolean exists = true;
+ while (exists && (tries < maxTries)) {
+ recursivelyDeleteDirectory(file);
+ tries++;
+ exists = file.exists();
+ if (exists) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
+ }
+ return !exists;
+ }
+
+ private static void recursivelyDeleteDirectory(File file) {
+ if (!file.exists()) {
+ return;
+ }
+
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ for (File child : files) {
+ recursivelyDeleteDirectory(child);
+ }
+ }
+ boolean success = file.delete();
+ if (!success) {
+ LOG.warn("Deletion of file: " + file.getAbsolutePath() + " failed");
+ }
+ }
+
+ /**
+ * create the directory
+ *
+ * @param file the directory to be created
+ */
+ public static void createDirectory(String file) {
+ File dir = new File(file);
+ dir.mkdirs();
+ }
+
+
+}
Added: aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.java?rev=1364831&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.java (added)
+++ aries/trunk/blueprint/blueprint-cm/src/test/java/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.java Mon Jul 23 23:06:01 2012
@@ -0,0 +1,138 @@
+/**
+ * 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.aries.blueprint.compendium.cm;
+
+import java.util.Hashtable;
+
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class ManagedServiceFactoryTest extends BaseTest {
+
+ @Override
+ protected String getBlueprintDescriptor() {
+ return "org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.xml";
+ }
+
+ @Test
+ public void test1() throws Exception {
+ ConfigurationAdmin ca = getOsgiService(ConfigurationAdmin.class);
+ Configuration cf = ca.createFactoryConfiguration("blueprint-sample-managed-service-factory", null);
+ Hashtable<String,String> props = new Hashtable<String,String>();
+ props.put("a", "5");
+ cf.update(props);
+
+ BundleContext context = getBundleContext();
+ ServiceReference sr = Helper.getOsgiServiceReference(context, Foo.class, "(key=foo1)", Helper.DEFAULT_TIMEOUT);
+ assertNotNull(sr);
+ Foo foo = (Foo) context.getService(sr);
+ assertNotNull(foo);
+ assertEquals(5, foo.getA());
+ assertEquals("default", foo.getB());
+ assertEquals("5", sr.getProperty("a"));
+ assertNull(sr.getProperty("b"));
+
+ props = new Hashtable<String,String>();
+ props.put("b", "foo");
+ cf.update(props);
+ Thread.sleep(500);
+
+ // No update of bean after creation
+ assertEquals(5, foo.getA());
+ assertEquals("default", foo.getB());
+
+ // Only initial update of service properties
+ assertEquals("5", sr.getProperty("a"));
+ assertNull(sr.getProperty("b"));
+ }
+
+ @Test
+ public void test2() throws Exception {
+ ConfigurationAdmin ca = getOsgiService(ConfigurationAdmin.class);
+ Configuration cf = ca.createFactoryConfiguration("blueprint-sample-managed-service-factory2", null);
+ Hashtable<String,String> props = new Hashtable<String,String>();
+ props.put("a", "5");
+ cf.update(props);
+
+ BundleContext context = getBundleContext();
+ ServiceReference sr = Helper.getOsgiServiceReference(context, Foo.class, "(key=foo2)", Helper.DEFAULT_TIMEOUT);
+ assertNotNull(sr);
+
+ Foo foo = (Foo) context.getService(sr);
+ assertNotNull(foo);
+ assertEquals(5, foo.getA());
+ assertEquals("default", foo.getB());
+ assertNull(sr.getProperty("a"));
+ assertNull(sr.getProperty("b"));
+
+ props = new Hashtable<String,String>();
+ props.put("b", "foo");
+ cf.update(props);
+
+ // Update after creation
+ Thread.sleep(500);
+ assertEquals(5, foo.getA());
+ assertEquals("foo", foo.getB());
+
+ // No update of service properties
+ assertNull(sr.getProperty("a"));
+ assertNull(sr.getProperty("b"));
+ }
+
+ @Test
+ public void test3() throws Exception {
+ ConfigurationAdmin ca = getOsgiService(ConfigurationAdmin.class);
+ Configuration cf = ca.createFactoryConfiguration("blueprint-sample-managed-service-factory3", null);
+ Hashtable<String,String> props = new Hashtable<String,String>();
+ props.put("a", "5");
+ cf.update(props);
+
+ BundleContext context = getBundleContext();
+ ServiceReference sr = Helper.getOsgiServiceReference(context, Foo.class, "(key=foo3)", Helper.DEFAULT_TIMEOUT);
+ assertNotNull(sr);
+
+ Foo foo = (Foo) context.getService(sr);
+ assertNotNull(foo);
+ assertEquals(5, foo.getA());
+ assertEquals("default", foo.getB());
+ assertEquals("5", sr.getProperty("a"));
+ assertNull(sr.getProperty("b"));
+
+ props = new Hashtable<String,String>();
+ props.put("b", "foo");
+ cf.update(props);
+
+ // Update after creation
+ Thread.sleep(500);
+ assertEquals(5, foo.getA());
+ assertEquals("foo", foo.getB());
+
+ // Update of service properties
+ assertEquals("5", sr.getProperty("a"));
+ assertEquals("foo", sr.getProperty("b"));
+ }
+
+}
Added: aries/trunk/blueprint/blueprint-cm/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/test/resources/log4j.properties?rev=1364831&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/test/resources/log4j.properties (added)
+++ aries/trunk/blueprint/blueprint-cm/src/test/resources/log4j.properties Mon Jul 23 23:06:01 2012
@@ -0,0 +1,42 @@
+## ------------------------------------------------------------------------
+## 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.
+## ------------------------------------------------------------------------
+
+#
+# The logging properties used for testing
+#
+log4j.rootLogger=DEBUG, out, file
+
+#log4j.logger.de.kalpatec.pojosr=DEBUG
+#log4j.logger.org.apache.camel.test.blueprint=DEBUG
+#log4j.logger.org.apache.camel=DEBUG
+#log4j.logger.org.apache.camel.blueprint=TRACE
+
+# CONSOLE appender not used by default
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+# MDC
+#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %-10.10X{camel.breadcrumbId} - %-10.10X{camel.exchangeId} - %-10.10X{camel.correlationId} - %-10.10X{camel.routeId} - %m%n
+
+# File appender
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.file=target/camel-test-blueprint.log
+log4j.appender.file.append=true
+log4j.appender.file.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+# MDC
+#log4j.appender.file.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %-10.10X{camel.breadcrumbId} - %-10.10X{camel.exchangeId} - %-10.10X{camel.correlationId} - %-10.10X{camel.routeId} - %m%n
Added: aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.xml
URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.xml?rev=1364831&view=auto
==============================================================================
--- aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.xml (added)
+++ aries/trunk/blueprint/blueprint-cm/src/test/resources/org/apache/aries/blueprint/compendium/cm/ManagedServiceFactoryTest.xml Mon Jul 23 23:06:01 2012
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+ 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.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0">
+
+ <cm:managed-service-factory id="managed-service-factory"
+ factory-pid="blueprint-sample-managed-service-factory"
+ interface="org.apache.aries.blueprint.compendium.cm.Foo">
+ <service-properties>
+ <entry key="key" value="foo1" />
+ <cm:cm-properties persistent-id="" />
+ </service-properties>
+ <cm:managed-component class="org.apache.aries.blueprint.compendium.cm.Foo">
+ <cm:managed-properties persistent-id="" />
+ <property name="a" value="1" />
+ <property name="b" value="default" />
+ </cm:managed-component>
+ </cm:managed-service-factory>
+
+ <cm:managed-service-factory id="managed-service-factory2"
+ factory-pid="blueprint-sample-managed-service-factory2"
+ interface="org.apache.aries.blueprint.compendium.cm.Foo">
+ <service-properties>
+ <entry key="key" value="foo2" />
+ </service-properties>
+ <cm:managed-component class="org.apache.aries.blueprint.compendium.cm.Foo">
+ <cm:managed-properties persistent-id="" update-strategy="container-managed" />
+ <property name="a" value="1" />
+ <property name="b" value="default" />
+ </cm:managed-component>
+ </cm:managed-service-factory>
+
+ <cm:managed-service-factory id="managed-service-factory3"
+ factory-pid="blueprint-sample-managed-service-factory3"
+ interface="org.apache.aries.blueprint.compendium.cm.Foo">
+ <service-properties>
+ <entry key="key" value="foo3" />
+ <cm:cm-properties persistent-id="" update="true"/>
+ </service-properties>
+ <cm:managed-component class="org.apache.aries.blueprint.compendium.cm.Foo">
+ <cm:managed-properties persistent-id="" update-strategy="container-managed" />
+ <property name="a" value="1" />
+ <property name="b" value="default" />
+ </cm:managed-component>
+ </cm:managed-service-factory>
+
+</blueprint>